I am just playing with images in WPF and i wrote a sample application which loads an image from hard disk and the should change the first 100 pixel in each line to red. But it doesn' do this and instead the generated iage has small redlined everywhere. I belive somewhere in the code, h and w are changed and hence the stride is not correct. But I can not find where is the problm. Any help appriciated.
The code is as follow:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestImageProcessing
{
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
class TransformImage
{
public static BitmapSource Transform(BitmapImage input)
{
var red = new PixelColor() { Blue = 0, Green = 0, Red =255, Alpha =128 };
var inputPixels = GetPixels(input);
var outPixel = new PixelColor[inputPixels.GetLength(0), inputPixels.GetLength(1)];
var output = new WriteableBitmap(input.PixelWidth, input.PixelHeight, input.DpiX, input.DpiY, input.Format, input.Palette);
for (int h = 0; h < input.PixelHeight; h++)
{
for (int w = 0; w < input.PixelWidth; w++)
{
if (h < 100)
{
outPixel[w, h] = red;
}
else
{
outPixel[w, h] = inputPixels[w, h];
}
}
}
PutPixels(output, outPixel);
return output;
}
[StructLayout(LayoutKind.Sequential)]
public struct PixelColor
{
public byte Blue;
public byte Green;
public byte Red;
public byte Alpha;
}
public static void PutPixels(WriteableBitmap bitmap, PixelColor[,] pixels)
{
int width = pixels.GetLength(0);
int height = pixels.GetLength(1);
bitmap.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * 4, 0);
}
public static PixelColor[,] GetPixels(BitmapSource source)
{
if (source.Format != PixelFormats.Bgra32)
{
source = new FormatConvertedBitmap(source, PixelFormats.Bgra32, null, 0);
}
PixelColor[,] pixels = new PixelColor[source.PixelWidth, source.PixelHeight];
int stride = source.PixelWidth * ((source.Format.BitsPerPixel + 7) / 8);
GCHandle pinnedPixels = GCHandle.Alloc(pixels, GCHandleType.Pinned);
source.CopyPixels(
new Int32Rect(0, 0, source.PixelWidth, source.PixelHeight),
pinnedPixels.AddrOfPinnedObject(),
pixels.GetLength(0) * pixels.GetLength(1) * 4,
stride);
pinnedPixels.Free();
return pixels;
}
}
}
Part of he above code comes from this post: Finding specific pixel colors of a BitmapImage
MainWindow.xaml:
<Window x:Class="TestImageProcessing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="550" Width="725">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="30px"/>
</Grid.RowDefinitions>
<Image x:Name="InImage" Grid.Row="0" VerticalAlignment="Top" Stretch="Uniform" />
<Image x:Name="OutImage" Grid.Row="1" VerticalAlignment="Top" Stretch="Uniform" />
<Button x:Name="Process" Content="Button" Grid.Row="2" Width="75" Click="Process_Click"/>
</Grid>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace TestImageProcessing
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Process_Click(object sender, RoutedEventArgs e)
{
BitmapImage input= new BitmapImage(new Uri(@"C:\tmp\test.jpg"));
InImage.Source=input;
OutImage.Source = TransformImage.Transform(input);
}
}
}