patterncsharpMinor
Adding filters to images
Viewed 0 times
imagesfiltersadding
Problem
Here is some code I wrote as part of a project that I am working on to learn C#. It is a class responsible for applying filters to images. In this case, my code offers filters such as sepia and grayscale (sorry, no Valencia for you Instagram users!). Any input on how it can be improved is appreciated.
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace ImageFilter
{
public static class ExtBitmap
{
private static Bitmap GetArgbCopy(Image sourceImage)
{
Bitmap bmpNew = new Bitmap(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bmpNew))
{
graphics.DrawImage(sourceImage, new Rectangle(0, 0, bmpNew.Width, bmpNew.Height), new Rectangle(0, 0, bmpNew.Width, bmpNew.Height), GraphicsUnit.Pixel);
graphics.Flush();
}
return bmpNew;
}
private static Bitmap ApplyColorMatrix(Image sourceImage, ColorMatrix colorMatrix)
{
Bitmap bmp32BppSource = GetArgbCopy(sourceImage);
Bitmap bmp32BppDest = new Bitmap(bmp32BppSource.Width, bmp32BppSource.Height, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bmp32BppDest))
{
ImageAttributes bmpAttributes = new ImageAttributes();
bmpAttributes.SetColorMatrix(colorMatrix);
graphics.DrawImage(bmp32BppSource, new Rectangle(0, 0, bmp32BppSource.Width, bmp32BppSource.Height),
0, 0, bmp32BppSource.Width, bmp32BppSource.Height, GraphicsUnit.Pixel, bmpAttributes);
}
bmp32BppSource.Dispose();
return bmp32BppDest;
}
public static Bitmap CopyWithTransparency(this Image sourceImage, byte alphaComponent = 100)
{
Bitmap bmpNew = GetArgbCopy(sourceImage);
BitmapData bmpData = b
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace ImageFilter
{
public static class ExtBitmap
{
private static Bitmap GetArgbCopy(Image sourceImage)
{
Bitmap bmpNew = new Bitmap(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bmpNew))
{
graphics.DrawImage(sourceImage, new Rectangle(0, 0, bmpNew.Width, bmpNew.Height), new Rectangle(0, 0, bmpNew.Width, bmpNew.Height), GraphicsUnit.Pixel);
graphics.Flush();
}
return bmpNew;
}
private static Bitmap ApplyColorMatrix(Image sourceImage, ColorMatrix colorMatrix)
{
Bitmap bmp32BppSource = GetArgbCopy(sourceImage);
Bitmap bmp32BppDest = new Bitmap(bmp32BppSource.Width, bmp32BppSource.Height, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bmp32BppDest))
{
ImageAttributes bmpAttributes = new ImageAttributes();
bmpAttributes.SetColorMatrix(colorMatrix);
graphics.DrawImage(bmp32BppSource, new Rectangle(0, 0, bmp32BppSource.Width, bmp32BppSource.Height),
0, 0, bmp32BppSource.Width, bmp32BppSource.Height, GraphicsUnit.Pixel, bmpAttributes);
}
bmp32BppSource.Dispose();
return bmp32BppDest;
}
public static Bitmap CopyWithTransparency(this Image sourceImage, byte alphaComponent = 100)
{
Bitmap bmpNew = GetArgbCopy(sourceImage);
BitmapData bmpData = b
Solution
In the world of
One of such examples would be the
You're also not consistent with the
Ideally it should look like this:
With such a lengthy parameter list you can use their names and write them in separate lines to improve readability.
In other places like where you use
The other APIs are very similar so the above suggestions apply to all of them.
Here I don't like the magic
The same applies to other loops like here:
Why
that you can use with the arrays:
```
const int colorCount = 4;
for (int i = 0; i < byteBuffer.Length; i += colorCount)
{
pixel = ~BitConverter.ToInt32(byteBuffer, i);
pixelBuffer = BitConverter.GetBytes(pixel);
byteBuffer[i + ColorOffset.Red] = pixelBuffer[ColorOffset.Red];
byteBuffer[i + ColorOffset.Green] = pixelBuffer[ColorOffset.Green];
byteBuffer[i + ColorOffset.Blue] = pi
Graphics and Bitmaps you can assume that virtually everything's disposable so you should also try to dispose everything you're working with.One of such examples would be the
ImageAttributes that you use in the ApplyColorMatrix and you don't dispose.You're also not consistent with the
using statement. Once you use it and the other time not like here:private static Bitmap ApplyColorMatrix(Image sourceImage, ColorMatrix colorMatrix)
{
Bitmap bmp32BppSource = GetArgbCopy(sourceImage);
Bitmap bmp32BppDest = new Bitmap(bmp32BppSource.Width, bmp32BppSource.Height, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bmp32BppDest))
{
ImageAttributes bmpAttributes = new ImageAttributes();
bmpAttributes.SetColorMatrix(colorMatrix);
graphics.DrawImage(bmp32BppSource, new Rectangle(0, 0, bmp32BppSource.Width, bmp32BppSource.Height),
0, 0, bmp32BppSource.Width, bmp32BppSource.Height, GraphicsUnit.Pixel, bmpAttributes);
}
bmp32BppSource.Dispose();
return bmp32BppDest;
}Ideally it should look like this:
private static Bitmap ApplyColorMatrix(Image sourceImage, ColorMatrix colorMatrix)
{
using (Bitmap bmp32BppSource = GetArgbCopy(sourceImage))
{
Bitmap bmp32BppDest = new Bitmap(bmp32BppSource.Width, bmp32BppSource.Height, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bmp32BppDest))
using(ImageAttributes bmpAttributes = new ImageAttributes())
{
bmpAttributes.SetColorMatrix(colorMatrix);
graphics.DrawImage(
image: bmp32BppSource,
destRect: new Rectangle(0, 0, bmp32BppSource.Width, bmp32BppSource.Height),
srcX: 0,
srcY: 0,
srcWidth: bmp32BppSource.Width,
srcHeight: bmp32BppSource.Height,
srcUnit: GraphicsUnit.Pixel,
imageAttrs: bmpAttributes
);
return bmp32BppDest;
}
}
}With such a lengthy parameter list you can use their names and write them in separate lines to improve readability.
In other places like where you use
LockBits there is a danger that if an exception is thrown the bits won't get unclocked anymore because there is no try/finally block e.g. the CopyWithTransparency method should be implemented this way:public static Bitmap CopyWithTransparency(this Image sourceImage, byte alphaComponent = 100)
{
Bitmap bmpNew = GetArgbCopy(sourceImage);
BitmapData bmpData = null;
try
{
bmpData = bmpNew.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
IntPtr ptr = bmpData.Scan0;
byte[] byteBuffer = new byte[bmpData.Stride * bmpNew.Height];
Marshal.Copy(ptr, byteBuffer, 0, byteBuffer.Length);
for (int k = 3; k < byteBuffer.Length; k += 4)
{
byteBuffer[k] = alphaComponent;
}
Marshal.Copy(byteBuffer, 0, ptr, byteBuffer.Length);
return bmpNew;
}
finally
{
if (bmpData != null) bmpNew.UnlockBits(bmpData);
}
}The other APIs are very similar so the above suggestions apply to all of them.
for (int k = 3; k < byteBuffer.Length; k += 4)
{
byteBuffer[k] = alphaComponent;
}Here I don't like the magic
3 and 4 and the variable k. We usually start with i unless the variable has a special meaning. In this case you could even use an a that would be much better (because it stands for alpha) then a k which doesn't mean anything and with two constants the code is much easier to understand:const int firstAlpha = 3;
const int colorComponentCount = 4;
for (int a = firstAlpha; a < byteBuffer.Length; a += colorComponentCount)
{
byteBuffer[a] = alphaComponent;
}The same applies to other loops like here:
for (int k = 0; k < byteBuffer.Length; k += 4)
{
pixel = ~BitConverter.ToInt32(byteBuffer, k);
pixelBuffer = BitConverter.GetBytes(pixel);
byteBuffer[k] = pixelBuffer[0];
byteBuffer[k + 1] = pixelBuffer[1];
byteBuffer[k + 2] = pixelBuffer[2];
}Why
+ 1 or + 2? Would you know it it two months? Use constnats like greenOffset or blueOffset etc. or create a helper class to store the offsets:class ColorOffset
{
public const int Red = 0;
public const int Green = 1;
public const int Blue = 2;
public const int Alpha = 3;
}that you can use with the arrays:
```
const int colorCount = 4;
for (int i = 0; i < byteBuffer.Length; i += colorCount)
{
pixel = ~BitConverter.ToInt32(byteBuffer, i);
pixelBuffer = BitConverter.GetBytes(pixel);
byteBuffer[i + ColorOffset.Red] = pixelBuffer[ColorOffset.Red];
byteBuffer[i + ColorOffset.Green] = pixelBuffer[ColorOffset.Green];
byteBuffer[i + ColorOffset.Blue] = pi
Code Snippets
private static Bitmap ApplyColorMatrix(Image sourceImage, ColorMatrix colorMatrix)
{
Bitmap bmp32BppSource = GetArgbCopy(sourceImage);
Bitmap bmp32BppDest = new Bitmap(bmp32BppSource.Width, bmp32BppSource.Height, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bmp32BppDest))
{
ImageAttributes bmpAttributes = new ImageAttributes();
bmpAttributes.SetColorMatrix(colorMatrix);
graphics.DrawImage(bmp32BppSource, new Rectangle(0, 0, bmp32BppSource.Width, bmp32BppSource.Height),
0, 0, bmp32BppSource.Width, bmp32BppSource.Height, GraphicsUnit.Pixel, bmpAttributes);
}
bmp32BppSource.Dispose();
return bmp32BppDest;
}private static Bitmap ApplyColorMatrix(Image sourceImage, ColorMatrix colorMatrix)
{
using (Bitmap bmp32BppSource = GetArgbCopy(sourceImage))
{
Bitmap bmp32BppDest = new Bitmap(bmp32BppSource.Width, bmp32BppSource.Height, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bmp32BppDest))
using(ImageAttributes bmpAttributes = new ImageAttributes())
{
bmpAttributes.SetColorMatrix(colorMatrix);
graphics.DrawImage(
image: bmp32BppSource,
destRect: new Rectangle(0, 0, bmp32BppSource.Width, bmp32BppSource.Height),
srcX: 0,
srcY: 0,
srcWidth: bmp32BppSource.Width,
srcHeight: bmp32BppSource.Height,
srcUnit: GraphicsUnit.Pixel,
imageAttrs: bmpAttributes
);
return bmp32BppDest;
}
}
}public static Bitmap CopyWithTransparency(this Image sourceImage, byte alphaComponent = 100)
{
Bitmap bmpNew = GetArgbCopy(sourceImage);
BitmapData bmpData = null;
try
{
bmpData = bmpNew.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
IntPtr ptr = bmpData.Scan0;
byte[] byteBuffer = new byte[bmpData.Stride * bmpNew.Height];
Marshal.Copy(ptr, byteBuffer, 0, byteBuffer.Length);
for (int k = 3; k < byteBuffer.Length; k += 4)
{
byteBuffer[k] = alphaComponent;
}
Marshal.Copy(byteBuffer, 0, ptr, byteBuffer.Length);
return bmpNew;
}
finally
{
if (bmpData != null) bmpNew.UnlockBits(bmpData);
}
}for (int k = 3; k < byteBuffer.Length; k += 4)
{
byteBuffer[k] = alphaComponent;
}const int firstAlpha = 3;
const int colorComponentCount = 4;
for (int a = firstAlpha; a < byteBuffer.Length; a += colorComponentCount)
{
byteBuffer[a] = alphaComponent;
}Context
StackExchange Code Review Q#158086, answer score: 3
Revisions (0)
No revisions yet.