Parse image size from JPEG - c#

I was wondering if there was an inexpensive way to get the width and height of a JPEG after loading an array of bytes.
I know JpegBitmapDecoder can get the JPEG's pixel width and height but it loads alot of information as well, which I assume would be an expensive operation.
Is there another way to get the width and height from the array of bytes without decoding it?
Thanks

For some unknown reason, instead of going to bed, I went to work on this.
Here's some code that solves this with minimal storage requirements.
void Main()
{
var filePath=#"path\to\my.jpg";
var bytes=File.ReadAllBytes(filePath);
var dimensions=GetJpegDimensions(bytes);
//or
//var dimensions=GetJpegDimensions(filePath);
Console.WriteLine(dimensions);
}
public static Dimensions GetJpegDimensions(byte[] bytes)
{
using(var ms=new MemoryStream(bytes))
{
return GetJpegDimensions(ms);
}
}
public static Dimensions GetJpegDimensions(string filePath)
{
using(var fs=File.OpenRead(filePath))
{
return GetJpegDimensions(fs);
}
}
public static Dimensions GetJpegDimensions(Stream fs)
{
if(!fs.CanSeek) throw new ArgumentException("Stream must be seekable");
long blockStart;
var buf = new byte[4];
fs.Read(buf, 0, 4);
if(buf.SequenceEqual(new byte[]{0xff, 0xd8, 0xff, 0xe0}))
{
blockStart = fs.Position;
fs.Read(buf, 0, 2);
var blockLength = ((buf[0] << 8) + buf[1]);
fs.Read(buf, 0, 4);
if(Encoding.ASCII.GetString(buf, 0, 4) == "JFIF"
&& fs.ReadByte() == 0)
{
blockStart += blockLength;
while(blockStart < fs.Length)
{
fs.Position = blockStart;
fs.Read(buf, 0, 4);
blockLength = ((buf[2] << 8) + buf[3]);
if(blockLength >= 7 && buf[0] == 0xff && buf[1] == 0xc0)
{
fs.Position += 1;
fs.Read(buf, 0, 4);
var height = (buf[0] << 8) + buf[1];
var width = (buf[2] << 8) + buf[3];
return new Dimensions(width, height);
}
blockStart += blockLength + 2;
}
}
}
return null;
}
public class Dimensions
{
private readonly int width;
private readonly int height;
public Dimensions(int width, int height)
{
this.width = width;
this.height = height;
}
public int Width
{
get{return width;}
}
public int Height
{
get{return height;}
}
public override string ToString()
{
return string.Format("width:{0}, height:{1}", Width, Height);
}
}

I've read a CodeProject article about it a couple years back :)
I'm not 100% sure how good it is, and haven't tested it myself, but the author's definitely happy with it; also his tests prove it's a LOT faster than reading the whole image, as you'd expect :)
Here's the article itself.. Hope it's what you need!
http://www.codeproject.com/KB/cs/ReadingImageHeaders.aspx
The piece of code you're looking for starts about here:
http://www.codeproject.com/KB/cs/ReadingImageHeaders.aspx#premain3
UPD: Also, check the comments in the bottom.. Especially the last (top) one there.. Might be useful to make it more generic
Also, more in-depth, advanced info can be picked up here: http://www.codeproject.com/KB/graphics/iptc.aspx

Related

Wrong generated TIf image using WriteableBitmap::WritePixels in c#

I changed pixel RGB value for a TIF image, but the generated tif image is not correct.
I use C# since there are some APIS for encoding and decoding TIF image format. My code is shown below.
public partial class Form1 : Form
{
private static int bytesPerPixel = 4;
private int width;
private int height;
byte[] bytes;
BitmapSource bitmapSource;
FormatConvertedBitmap convertedBitmap;
public Form1()
{
InitializeComponent();
}
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{ .....
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
// Open the selected file to read.
string fileName = openFileDialog1.FileName;
pictureBox1.Load(fileName);
// Open a Stream and decode a TIFF image
Stream imageStreamSource = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
TiffBitmapDecoder decoder = new TiffBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
bitmapSource = decoder.Frames[0];
convertedBitmap = new FormatConvertedBitmap(bitmapSource, PixelFormats.Bgra32, null, 0);
bytesPerPixel = (convertedBitmap.Format.BitsPerPixel + 7) / 8;
width = convertedBitmap.PixelWidth;
height = convertedBitmap.PixelHeight;
bytes = new byte[width * height * bytesPerPixel];
convertedBitmap.CopyPixels(bytes, (convertedBitmap.PixelWidth * convertedBitmap.Format.BitsPerPixel + 7) / 8, 0);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
Color color = GetPixel(bytes, i,j, bytesPerPixel);
if (i < width / 2 || j < height / 2)
setPixel(bytes, i, j, bytesPerPixel, (byte)(0), (byte)(0), (byte)(0));
else {
setPixel(bytes, i, j, bytesPerPixel, (byte)(255), (byte)(255), (byte)(255));
}
}
}
}
}
private static Color GetPixel(byte[] bgraBytes, int x, int y, int width)
{
var index = (y * (width * bytesPerPixel) + (x * bytesPerPixel));
return Color.FromArgb(
bgraBytes[index + 3],
bgraBytes[index + 2],
bgraBytes[index + 1],
bgraBytes[index]);
}
private static void setPixel(byte[] bytes, int x, int y, int width, byte r, byte g, byte b) {
var index = (y * (width * bytesPerPixel) + (x * bytesPerPixel));
bytes[index] = r; bytes[index + 1] = g; bytes[index + 2] = b;
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{ ................
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
int stride = width *8;
// Define the image palette
BitmapPalette myPalette = BitmapPalettes.WebPalette;
// Creates a new empty image with the pre-defined palette
var image = new WriteableBitmap(convertedBitmap);
image.WritePixels(new Int32Rect(0, 0, convertedBitmap.PixelWidth, convertedBitmap.PixelHeight), bytes,
(convertedBitmap.PixelWidth * convertedBitmap.Format.BitsPerPixel + 7) / 8, 0);
FileStream stream = new FileStream(saveFileDialog1.FileName, FileMode.Create);
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
TextBlock myTextBlock = new TextBlock();
myTextBlock.Text = "Codec Author is: " + encoder.CodecInfo.Author.ToString();
encoder.Compression = TiffCompressOption.Zip;
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(stream);
stream.Dispose();
}
}
}
In the code, a tif image is read and its pixel RGB is copied to the byte[] bytes which is a class field member. After modifying all pixel RGB color (by 255 -), the bytes is then used to initilize another image and writen to the disk.
There is no error during runtime, but the generated tif image is not the same as i expected. The generated image is the same as original one, which is not correct.
Could anyone explain the reason that the generated image the same as input one? It seems the writePixel() does not take effect. During debug, i do find the bytes parameter in writePixel has been updated. I do not know the reason, as i am not very skill at C#, nor Image format. The original code are from
https://msdn.microsoft.com/en-us/library/aa969817%28v=vs.110%29.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
and
TIFF file parsing in C#

libtiff.net writeScanLine returns false

I'm using libtiff.net to make a tiff from a jpeg.
The problem apears when I try to write, because the tiff.writeScanLine returns false, meaning the image isn't written in the tiff.
Why is this happening? And how can I figure out what's wrong?
Here's the code:
private bool creatingTiff()
{
using (Bitmap bmp = new Bitmap(targetFile))
{
using (Tiff tif = Tiff.Open("BitmapTo24BitColorTiff.tif", "w"))
{
byte[] raster = getImageRasterBytes(bmp, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
tif.SetField(TiffTag.IMAGEWIDTH, bmp.Width);
tif.SetField(TiffTag.IMAGELENGTH, bmp.Height);
tif.SetField(TiffTag.COMPRESSION, Compression.OJPEG);
tif.SetField(TiffTag.PHOTOMETRIC, Photometric.YCBCR);
tif.SetField(TiffTag.SUBFILETYPE, 0);
tif.SetField(TiffTag.ROWSPERSTRIP, bmp.Height);
tif.SetField(TiffTag.ORIENTATION, BitMiracle.LibTiff.Classic.Orientation.TOPLEFT);
tif.SetField(TiffTag.XRESOLUTION, bmp.HorizontalResolution);
tif.SetField(TiffTag.YRESOLUTION, bmp.VerticalResolution);
tif.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.INCH);
tif.SetField(TiffTag.BITSPERSAMPLE, 8);
tif.SetField(TiffTag.SAMPLESPERPIXEL, 3);
tif.SetField(TiffTag.JPEGIFOFFSET, 768);
tif.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
for (int i = 0, offset = 0; i < bmp.Height; i++)
{
bool b = tif.WriteScanline(raster, offset, i, 0);
Console.WriteLine("write succes: " + b);
offset += stride;
}
}
System.Diagnostics.Process.Start("BitmapTo24BitColorTiff.tif");
return true;
}
}
private static byte[] getImageRasterBytes(Bitmap bmp, System.Drawing.Imaging.PixelFormat format)
{
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
byte[] bits = null;
try
{
// Lock the managed memory
BitmapData bmpdata = bmp.LockBits(rect, ImageLockMode.ReadWrite, format);
// Declare an array to hold the bytes of the bitmap.
bits = new byte[bmpdata.Stride * bmpdata.Height];
// Copy the values into the array.
System.Runtime.InteropServices.Marshal.Copy(bmpdata.Scan0, bits, 0, bits.Length);
// Release managed memory
bmp.UnlockBits(bmpdata);
}
catch
{
return null;
}
return bits;
}
private static void convertSamples(byte[] data, int width, int height)
{
int stride = data.Length / height;
const int samplesPerPixel = 3;
for (int y = 0; y < height; y++)
{
int offset = stride * y;
int strideEnd = offset + width * samplesPerPixel;
for (int i = offset; i < strideEnd; i += samplesPerPixel)
{
byte temp = data[i + 2];
data[i + 2] = data[i];
data[i] = temp;
}
}
}
The tif-tags are written, but the image itself isn't. Perhaps if someone can point me in the direction of the library developers blog (BitMiracle), I can direct my problem to them directly.
I think your code has the following errors:
You can not use Compression.OJPEG for new images. Old-JPEGs can only be de-compressed.
You probably should not specify TiffTag.JPEGIFOFFSET value by hand. The library will specify proper value itself.
You are trying to write the whole strip using WriteScanline method. You should use WriteEncodedStrip instead.
It also helps to review warnings emitted by the library (it emits them into console).

c# image filter parallel.for takes longer time [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
here is the code is there any way to make it faster cause its slowerden single
public Bitmap pSetInvert(Bitmap _currentBitmap)
{
Bitmap temp = (Bitmap)_currentBitmap;
Bitmap bmap = (Bitmap)temp.Clone();
Color c;
Parallel.For(0, bmap.Width, i =>
{
lock (bmap)
{
for (int j = 0; j < bmap.Height; j++)
{
c = bmap.GetPixel(i, j);
bmap.SetPixel(i, j, Color.FromArgb(255 - c.R, 255 - c.G, 255 - c.B));
}
}
});
return (Bitmap)bmap.Clone();
}
By using lock you are making parallel part of your code to work serially, exactly like a single thread application with synchronization overhead so it actually would be slower.
here is a helper class that access bitmap data directly and you can manipulate image in concurrently.
FastImage Helper Class:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
namespace ImageManipulation
{
class FastImage : IDisposable
{
private Bitmap _buffer;
private byte[] _rawData;
private GCHandle _rawHandle;
private int _formatSize;
private int _width;
private int _height;
public int Width
{
get { return _width; }
}
public int Height
{
get { return _height; }
}
public byte[] GetRawData()
{
return _rawData;
}
public byte this[int index]
{
get { return _rawData[index]; }
set { _rawData[index] = value; }
}
public Color this[int x, int y]
{
get
{
return GetPixel(x, y);
}
set
{
SetPixel(x, y, value);
}
}
public Color GetPixel(int x, int y)
{
var offset = y*_width*_formatSize;
offset += x*_formatSize;
return Color.FromArgb(_rawData[offset + 3], _rawData[offset + 2], _rawData[offset + 1], _rawData[offset]);
}
public void SetPixel(int x, int y, Color value)
{
var offset = y*_width*_formatSize;
offset += x*_formatSize;
_rawData[offset] = value.B;
_rawData[offset + 1] = value.G;
_rawData[offset + 2] = value.R;
_rawData[offset + 3] = value.A;
}
private FastImage() { }
public static FastImage Create(Image source)
{
var image = new FastImage();
var bmpSource = new Bitmap(source);
var bmpData = bmpSource.LockBits(new Rectangle(0, 0, source.Width, source.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmpSource.PixelFormat);
image._width = source.Width;
image._height = source.Height;
image._formatSize = 4;
var stride = bmpSource.Width * image._formatSize;
image._rawData = new byte[stride * bmpSource.Height];
image._rawHandle = GCHandle.Alloc(image._rawData, GCHandleType.Pinned);
var pointer = Marshal.UnsafeAddrOfPinnedArrayElement(image._rawData, 0);
image._buffer = new Bitmap(bmpSource.Width, bmpSource.Height, stride, PixelFormat.Format32bppArgb /*bmpSource.PixelFormat*/, pointer);
bmpSource.UnlockBits(bmpData);
var graphics = Graphics.FromImage(image._buffer);
graphics.DrawImageUnscaledAndClipped(bmpSource, new Rectangle(0, 0, source.Width, source.Height));
graphics.Dispose();
return image;
}
public void Dispose()
{
_rawHandle.Free();
_buffer.Dispose();
}
public void Save(Stream stream)
{
_buffer.Save(stream, ImageFormat.Bmp);
}
public Bitmap ToBitmap()
{
return (Bitmap)_buffer.Clone();
}
}
}
and here is your code using FastImage class:
public Bitmap pSetInvert(Bitmap _currentBitmap)
{
using (var bmap = FastImage.Create(_currentBitmap))
{
Parallel.For(0, bmap.Width, i =>
{
for (int j = 0; j < bmap.Height; j++)
{
var c = bmap.GetPixel(i, j);
bmap.SetPixel(i, j, Color.FromArgb(255 - c.R, 255 - c.G, 255 - c.B));
}
});
return bmap.ToBitmap();
}
}
The lock in the Parallel.For is going to cause the code to run slower than with a single-threaded loop. The lock only allows one thread at a time to do useful work, with the added cost of acquiring the lock.
Additionally, GetPixel and SetPixel are extremely slow. They are also not guaranteed to be thread-safe, which is probably why you are getting the InvalidOperationException
Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
http://msdn.microsoft.com/en-us/library/System.Drawing.Bitmap(v=vs.110).aspx
Have a look instead at WriteableBitmap. Though the class was introduced with WPF, you can use it from a variety of environments. I recently used it in a console application. WriteableBitmap can be converted to a standard bitmap if needed, or written to a ".bmp" file.
Alternatively, you can use unsafe code to directly access the Bitmap buffer.
If you need to, you can use multiple threads for either WriteableBitmap or unsafe access to the Bitmap buffer since you are directly reading/writing memory.
Here are two versions of your filter routine you can play with. They take the image of one PictureBox and after running through the filter assign it to a second PictureBox.
The first one uses LockBits and can do 10.000 (!) loops for a ca 400x400 image in 40 seconds on my machine.
The second uses Parallel.For in addition to the LockBits and does the same job in 35 seconds here.
Of course these timings are strongly influenced by overhead (and maybe by dumb bugs I made.) But really, using Lockbits is key to speed here as there is so little to 'compute' the parallelization management itself eats up most of the cores' time..
using System.Runtime.InteropServices;
// ..
public void filter1()
{
if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
Bitmap bmp = new Bitmap(pictureBox1.Image);
Size s1 = bmp.Size;
PixelFormat fmt1 = bmp.PixelFormat;
Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, fmt1);
byte bpp = 4; // <<-------------------set to 3 for 24bbp !!
int size1 = bmpData.Stride * bmpData.Height;
byte[] data = new byte[size1];
Marshal.Copy(bmpData.Scan0, data, 0, size1);
for (int y = 0; y < s1.Height; y++)
{
for (int x = 0; x < s1.Width; x++)
{
int index = y * bmpData.Stride + x * bpp;
data[index + 0] = (byte) (255 - data[index + 0]); // Blue
data[index + 1] = (byte) (255 - data[index + 1]); // Green
data[index + 2] = (byte) (255 - data[index + 2]); // Red
data[index + 3] = 255; // Alpha, comment out for 24 bpp!
}
}
Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
bmp.UnlockBits(bmpData);
pictureBox2.Image = bmp;
}
public void filter2()
{
if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
Bitmap bmp1 = new Bitmap(pictureBox1.Image);
Size s1 = bmp1.Size;
Bitmap bmp2 = new Bitmap(s1.Width, s1.Height);
PixelFormat fmt1 = bmp1.PixelFormat;
Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);
BitmapData bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, fmt1);
BitmapData bmpData2 = bmp2.LockBits(rect, ImageLockMode.WriteOnly, fmt1);
byte bpp = 4; // set to 3 for 24bbp !!
int size1 = bmpData1.Stride * bmpData1.Height;
byte[] data1 = new byte[size1];
byte[] data2 = new byte[size1];
Marshal.Copy(bmpData1.Scan0, data1, 0, size1);
Marshal.Copy(bmpData2.Scan0, data2, 0, size1);
int degreeOfParallelism = Environment.ProcessorCount - 1;
var options = new ParallelOptions();
options.MaxDegreeOfParallelism = degreeOfParallelism;
Parallel.For(0, bmp1.Width, options, y =>
{
{
for (int x = 0; x < s1.Width; x++)
{
int index = y * bmpData1.Stride + x * bpp;
data2[index + 0] = (byte)(255 - data1[index + 0]); // Blue
data2[index + 1] = (byte)(255 - data1[index + 1]); // Green
data2[index + 2] = (byte)(255 - data1[index + 2]); // Red
data2[index + 3] = 255; // Alpha, comment out for 24 bpp!
}
}
});
Marshal.Copy(data2, 0, bmpData2.Scan0, data2.Length);
bmp1.UnlockBits(bmpData1);
bmp2.UnlockBits(bmpData2);
pictureBox2.Image = bmp2;
}
Note that the 2nd filter routine needs to work on a second Bitmap for general purpose filter algorithms. This simple inversion filter doesn't really need it, but once you write things that access neighbouring pixels like eg.g a blur filter you do..
Also note the order of the channel bytes!

ZXing still has a memory leak. Even after releasing the Global Alloc

In this post: Possible memory leak in Zxing's System.Drawing.Bitmap a question is asked about a memory leak in the ZXing library. I've downloaded and amended the library with the free of the allocated memory. I've even introduced using(){} statements where applicable but I still get a memory leak.
I have a suspicion. Does the Marshal.Copy maybe do more then just copy the data from source to destination. Do I maybe also have to free the destination after the copy?
As you can see in the code below I even tried allocating the buffer only once and only reallocating it when an image larger than the previous one is requested, but that did not solve the problem.
Regards
Paul
My altered code:
using System;
using MonoTouch.UIKit;
using MonoTouch.CoreGraphics;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace System.Drawing
{
public class Bitmap : IDisposable
{
byte[] pixelData = new byte[0];
int width = 0;
int height = 0;
static IntPtr m_BufferPointer = default(IntPtr);
static int m_Size;
/// <summary>
/// Reallocs the buffer when it becomes too small
/// </summary>
private IntPtr ReallocBuffer(int size)
{
if(m_BufferPointer != default(IntPtr))
{
if(m_Size < size)
{
Marshal.FreeHGlobal(m_BufferPointer);
m_BufferPointer = Marshal.AllocHGlobal(size);
}
}
else
{
m_BufferPointer = Marshal.AllocHGlobal(size);
}
m_Size = size;
return m_BufferPointer;
}
public Bitmap (UIImage image)
{
UIImage backingImage = image;
IntPtr rawData;
using (CGImage imageRef = backingImage.CGImage)
{
width = imageRef.Width;
height = imageRef.Height;
using (CGColorSpace colorSpace = CGColorSpace.CreateDeviceRGB ())
{
int size = height * width * 4;
rawData = ReallocBuffer(size); //Marshal.AllocHGlobal (height * width * 4);
using (CGContext context = new CGBitmapContext (rawData, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.PremultipliedLast))
{
context.DrawImage (new RectangleF (0.0f, 0.0f, (float)width, (float)height), imageRef);
pixelData = new byte[height * width * 4];
Marshal.Copy (rawData, pixelData, 0, pixelData.Length);
}
}
}
}
private static int CountCalled;
private static int LastCountCalled = 20000000; //30411000;
public Color GetPixel (int x, int y)
{
try
{
CountCalled++;
if (CountCalled - LastCountCalled > 100000)
{
Debug.WriteLine (CountCalled);
LastCountCalled += 1000000;
}
byte bytesPerPixel = 4;
int bytesPerRow = width * bytesPerPixel;
int rowOffset = y * bytesPerRow;
int colOffset = x * bytesPerPixel;
int pixelDataLoc = rowOffset + colOffset;
Color ret = Color.FromArgb (pixelData [pixelDataLoc + 3], pixelData [pixelDataLoc + 0], pixelData [pixelDataLoc + 1], pixelData [pixelDataLoc + 2]);
return ret;
}
catch (Exception ex)
{
Console.WriteLine ("Req: {0}x{1}", x, y);
throw ex;
}
}
#region IDisposable implementation
public void Dispose ()
{
pixelData = null;
GC.Collect(0);
}
#endregion
}
}
You need to free the native buffer, CGBitmapContext won't do it for you:
IntPtr rawData = Marshal.AllocHGlobal (height * width * 4);
try {
using (CGContext context = new CGBitmapContext (rawData, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.PremultipliedLast))
{
context.DrawImage (new RectangleF (0.0f, 0.0f, (float)width, (float)height), imageRef);
pixelData = new byte[height * width * 4];
Marshal.Copy (rawData, pixelData, 0, pixelData.Length);
}
} finally {
Marshal.FreeHGlobal (rawData);
}
Updated according to Jonathan.Peppers try-finally suggestion in the comments

how to read description for the code

hi i send some c# code this is get from imagealg.dll file the class name is diff code is given below how to get description for this code.
public sealed class Diff
{
// Fields
private int diff;
private Bitmap overlayImage;
private Bitmap overlayImage1;
// Methods
public Diff()
{
}
public Diff(Bitmap overlayImage, Bitmap overlayImage1)
{
this.overlayImage = overlayImage;
this.overlayImage1 = overlayImage1;
}
public int Apply(Bitmap srcImg, Bitmap dstImg)
{
int width = srcImg.Width;
int height = srcImg.Height;
int num3 = dstImg.Width;
int num4 = dstImg.Height;
PixelFormat format = (srcImg.PixelFormat == PixelFormat.Format8bppIndexed) ? PixelFormat.Format8bppIndexed : PixelFormat.Format24bppRgb;
BitmapData data = srcImg.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, format);
BitmapData ovrData = dstImg.LockBits(new Rectangle(0, 0, num3, num4), ImageLockMode.ReadOnly, format);
this.ProcessFilter(data, ovrData, format);
dstImg.UnlockBits(ovrData);
srcImg.UnlockBits(data);
return this.diff;
}
public void ApplyInPlace(Bitmap img)
{
int width = img.Width;
int height = img.Height;
if (((img.PixelFormat != this.overlayImage.PixelFormat) || (width != this.overlayImage.Width)) || (height != this.overlayImage.Height))
{
throw new ArgumentException();
}
if ((img.PixelFormat != PixelFormat.Format8bppIndexed) && (img.PixelFormat != PixelFormat.Format24bppRgb))
{
throw new ArgumentException();
}
BitmapData bitmapdata = img.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
img.UnlockBits(bitmapdata);
}
public int difference()
{
return this.diff;
}
private unsafe void ProcessFilter(BitmapData data, BitmapData ovrData, PixelFormat fmt)
{
int width = data.Width;
int height = data.Height;
int num3 = (fmt == PixelFormat.Format8bppIndexed) ? 1 : 3;
int num4 = width * num3;
int num5 = data.Stride - num4;
byte* numPtr = (byte*) data.Scan0.ToPointer();
byte* numPtr2 = (byte*) ovrData.Scan0.ToPointer();
this.diff = 0;
for (int i = 0; i < height; i++)
{
int num8 = 0;
while (num8 < num4)
{
int num6 = numPtr[0] - numPtr2[0];
string str = Convert.ToString(numPtr[0]);
string str2 = Convert.ToString(numPtr2[0]);
if (num6 != 0)
{
this.diff++;
}
num8++;
numPtr++;
numPtr2++;
}
numPtr += num5;
numPtr2 += num5;
}
}
// Properties
public Bitmap OverlayImage
{
get
{
return this.overlayImage;
}
set
{
this.overlayImage = value;
}
}
}
It sounds like you've recently received and/or been asked to use a library containing code that you don't quite understand. Unfortunately, if the source isn't properly documented, you only have two choices:
Go back to whomever or wherever you got the code from and ask them for proper documentation. Every piece of source code that you receive should come with documentation.
Study the code carefully and try to figure out what it's doing and how you are supposed to use it. This is somewhat closer to "reverse-engineering" the library (except that you have the source), and it's usually reserved as a last-ditch effort.
In fact, if any of us were to try and answer this question, that's all we could do is read and interpret the code you've posted. Is there something specific that you don't understand and are seeking clarification about?
And finally, remember this as a lesson to yourself. Whenever you write code, make sure that you take the time to document it properly so you don't put someone else who tries to use your code in the same situation that you're in now.
You'll be happy to know that the code doesn't do anything particularly significant. The Apply method sets up and calls ProcessFilter, which does a comparison of the two images and returns a count of the number of pixels that differ between the two.
The ApplyInPlace method does nothing.
And I feel sorry for the poor programmer who inherits this code and has to maintain it, what with all those useful variable names like num4 and num6.
It is my fondest wish that the programmer who brought this abomination into the world has been permanently banned from ever touching another keyboard.

Categories