Latest News
Mar 27, 2017, 9:16 AM

There are actually two different types of FOR loops included in C#. The first is the basic for iteration loop. The following code shows an example of a basic for iteration loop:

for(int i = 0; i < 100; i++)
{
Console.WriteLine(i.ToString());
}

Now, let’s dissect this a little bit so you can understand what’s going on here. The first thing done in this for loop is to declare the variable i as n integer and initialize it to 0. This is shown in the code above by “int I = 0”. This variable is often called the ITERATOR variable. The next piece is a comparison operation. As you should already know, comparison operations are Boolean operations that result in a true or a false. In this case, the comparison operation is represented by “i < 100”. This is telling the for loop to continue until the value of the variable i is equal to or greater than 100. Finally, “i++” tells the for loop to increment the value of i with each iteration. The only thing I haven’t explained is what’s contained within the for loop, “Console.WriteLine(i.ToString());”, this is the code to be executed on each iteration of the loop. In this case, we are outputting the value of i to the console window. Now that we’ve covered a basic for iteration loop, let’s take a quick peek at another for loop, the FOREACH iteration loop. Let’s say we have a list of integers:

List theList = newList();

Now we can write this:

foreach(List val in theList)
{
Console.WriteLine(val.ToString());
}

This is entirely different from the basic FOR iteration loop in that we aren’t declaring an iterator variable. This will parse through the entire list of integers one at a time and perform the necessary code on each. The benefit to the FOREACH loop is that we don’t have to determine how many elements are in the list, but we do have to have a list to parse through. The basic FOR loop doesn’t necessarily require a list to parse through, as is the case in the example I provided above. There is a caveat to be warned about when using a FOREACH loop. If you add or remove elements from within the list while it is being parsed by the FOREACH loop, it will cause an error. To avoid this error, anytime you know you will be modifying the list, you should use the basic FOR loop instead. Using our previous list of integers, the following is an example of this:

for(int i = 0; i < theList.Count; i++)
{
Console.WriteLine(theList[i].ToString());
theList.RemoveAt(i);
}

There are several things you’ll notice about this example that is slightly different from previous examples. First, instead of only going to 100, we’re getting a count of the elements from theList. This is to avoid certain potentially fatal memory leaks or errors. Secondly, we’re accessing the value using it’s index, which is shown by “theList[i]”. The variable i, in this case, is being used as the index value. NOTE: List<> used in this tutorial is a generic collection type found in System.Collections.Generic namespace.

Mar 27, 2017, 8:57 AM

When transferring images across the internet, many things can occur to break the transfer leaving partially corrupted image files as a result. These partially corrupted images are often able to be viewed in virtually any image viewer without causing any errors to be displayed. To find these partially corrupted files, some might resort to visually inspecting every file, a process that many companies simply cannot afford. This tutorial will walk you through creating an ImageFile class that can be used to detect partially corrupt images. Before we get into the code, there are a few things you should take note of;

  • This code only works with PNGs, JPGs, JPEGs, and GIFs.
  • This code does not care about file extensions, it uses the files data signature to determine how to process it.
  • Some images may be identified by this code as partially corrupt when they are in fact whole. (During testing it was discovered that images from one specific camera were always identified as partially corrupt. This is because the camera ignores the file specifications requiring certain bits at the end of the file, and adds its own junk there.)
  • Some partially corrupt images will not be identified by this code because they may still have the proper end bits. This will almost always be the case if the file was opened and resaved using any image editor and some image viewers after the corruption occurred.
  • This code also includes null bit removal code. In some rare instances, null bits are appended to the end of the file during file transfer. These null bits can cause an image file to be identified as partial when it is in fact, complete. The null bit removal code removes the null bits before the file is processed. This can be easily commented out with no harm to the rest of the program.
  • This code does NOT tell you if the entire file is corrupt. To do that, simply open the file using an Image object, if the whole file is corrupt it will throw an error.
  • This code was written for use in a Dynamic Linked Library project, so you will need to write other code to work with this if you want to use or test it.

We’ll start with our using statements and the basic class definition

using System.IO;

namespace ImageUtilities
{
public class ImageFile
{
}
}

The only using statement we’ll need is the System.IO class. We’ll be using this class to work with the files on a byte by byte basis. Then of course is our class container. You may feel free to change the names of the namespace or the class as you see fit. Add the following variables and properties to the top of the class

private readonly string _filename = string.Empty;
public string FileName { get { return _filename; } }

private ImageFileType _fileType = ImageFileType.FileNotFound;
public ImageFileType FileType { get { return _fileType; } }
private bool _fileComplete = false;
public bool FileComplete { get { return _fileComplete; } }

This class is designed so that it only performs the processing once and only when the class is instantiated. To facilitate this we use private variables with public get accessors. This means that once the class is instantiated its data cannot be changed. You will need to instantiate a copy of this class for each file to be processed.

#region Signatures
// 89 50 4E 47 0D 0A 1A 0A
private readonly byte[] _pngSignature = {137, 80, 78, 71, 13, 10, 26, 10};
// FF D8 FF
private readonly byte[] _jpgSignature = {255, 216, 255};
// 47 49 46 38 37 61
private readonly byte[] _gifaSignature = {71, 73, 70, 56, 55, 97};
// 47 49 46 38 39 61
private readonly byte[] _gifbSignature = {71, 73, 70, 56, 57, 97};
#endregion

These are the file signatures for each of the image file formats that this code can work with. The values in the comments are the hexadecimal equivalents to the values in the variable definitions.

#region EndBytes
// 49 45 4E 44 AE 42 60 82
private readonly byte[] _pngEnd = {73, 69, 78, 68, 174, 66, 96, 130};
// FF D9 FF FF
private readonly byte[] _jpgEndA = {255, 217, 255, 255};
// FF D9
private readonly byte[] _jpgEndB = {255, 217};
// 00 3B
private readonly byte[] _gifEnd = {0, 59};
#endregion

These are the byte signatures that should appear at the end of the files. Just as with the signatures, the values in the comments are the hexadecimal equivalents to the values in the definitions. You may note that there are two signatures for GIF and two end bytes for JPG. This is because there are multiple versions of these file format specifications. JPG actually uses one more byte in its signature. The fourth JPG signature byte specifies the JPG version, but all the versions I found, use one of two end bytes so I chose to ignore this last signature byte.

public ImageFile(string filename)
{
_filename = filename;
if(NeedsTrim()) TrimFile();
SetFileType();
if(_fileType != ImageFileType.FileNotFound && _fileType != ImageFileType.NotRecognized)
{
SetFileComplete();
}
}

This is the only constructor that we’ll provide for this class, which means that you must specify a file name when instantiating the class. Take note that file name here means the entire path and name of the file in the proper system path format. The order of operations in this is important to ensure that the file gets processed correctly. If you do not wish to trim the file, comment out the first if statement in the function.

private void SetFileType()
{
if(File.Exists(_filename))
{
var buffer = newbyte[20];
using(var fs = newFileStream(_filename, FileMode.Open))
{
if(fs.Length > 20)
fs.Read(buffer,0,20);
else
fs.Read(buffer, 0, (int)fs.Length);
}
if(MatchBytes(buffer, _pngSignature, ImageFileType.Png)) return;
if(MatchBytes(buffer, _jpgSignature, ImageFileType.Jpg)) return;
if(MatchBytes(buffer, _gifaSignature, ImageFileType.GifA)) return;
if(MatchBytes(buffer, _gifbSignature, ImageFileType.GifB)) return;
_fileType = ImageFileType.NotRecognized;
}
else
{
_fileType = ImageFileType.FileNotFound;
}
}

private bool MatchBytes(byte[] buffer, byte[] comp, ImageFileType fType)
{
for(var i = 0; i < comp.Length; i++)
{
if(buffer[i] != comp[i]) returnfalse;
}
_fileType = fType;
return true;
}

These two functions determine what type of image file this is using the file’s byte signature. Because of the various versions of each file format, we can not assume that the file’s extension is accurate. I’ve also found instances where images created by certain graphical editors are given a JPG extension but are actually PNG files internally.

private void SetFileComplete()
{
if(File.Exists(_filename))
{
switch(FileType)
{
case ImageFileType.Png:
SetComplete(_pngEnd);
break;
case ImageFileType.Jpg:
SetComplete(_jpgEndA);
SetComplete(_jpgEndB);
break;
case ImageFileType.GifA:
case ImageFileType.GifB:
SetComplete(_gifEnd);
break;
}
}
}

private void SetComplete(byte[] endBits)
{
var buffer = new byte[endBits.Length];
using(var fs = newFileStream(_filename, FileMode.Open))
{
if(fs.Length > endBits.Length)
{
fs.Seek((int)fs.Length - endBits.Length, 0);
fs.Read(buffer, 0, endBits.Length);
}
else
{
fs.Read(buffer, 0, (int)fs.Length);
}
if(MatchEndBytes(buffer, endBits)) return;
}
}

private bool MatchEndBytes(byte[] buffer,byte[] comp)
{
for(var i = 1; i < comp.Length; i++)
{
if(buffer[buffer.Length - i] != comp[comp.Length - i]) return false;
}
_fileComplete = true;
return true;
}

These three functions look at the last several bytes in the file to see if they match the file type’s end byte signature and sets the file completed Boolean accordingly. It’s written in this manner to allow one image type to have multiple signatures and/or multiple end byte signatures. Note also, that even if the image type has multiple possible end bytes, only one end byte must match to be considered a complete file.

public enum ImageFileType
{
FileNotFound,
NotRecognized,
Png,
Jpg,
GifA,
GifB
}

This is the enum that we’ve been using throughout this file that allows us to track what type of image file this is. This should be declared outside the class but within the same namespace.

private bool NeedsTrim()
{
using(var fs = newFileStream(_filename, FileMode.Open))
{
if(fs.Length > 0)
{
fs.Seek(fs.Length-1, 0);
var b = fs.ReadByte();
return b == 0;
}
return false;
}
}

private void TrimFile()
{
byte[] buffIn;
using(var fs = newFileStream(_filename, FileMode.Open))
{
buffIn = new byte[fs.Length];
fs.Read(buffIn, 0, (int)fs.Length);
}
var index = FindFirstNull(buffIn);
if(index < 0) return;
var buffOut = new byte[index];
for(int i = 0; i < index; i++)
{
buffOut[i] = buffIn[i];
}
using(var fs = newFileStream(_filename, FileMode.Create))
{
foreach(byte b in buffOut)
{
fs.WriteByte(B);
}
}
}

private int FindFirstNull(byte[] buffer)
{
for(var i = buffer.Length - 1; i > 0; i--)
{
if(buffer[i] != 0) return i + 1;
}
return -1;
}

Finally, these three methods are used to detect and trim null values from the end of the file. If you commented out or deleted the appropriate line in the code above, then these methods do not need to be included for the class to operate. Null values being left at the end of an image file is a rare occurrence caused by faulty software. In my instance, our end users have a program that uploads images in large chunks. If the last chunk isn’t as large as the specified chunk size, the program fills in the rest with nulls. These nulls can prevent a complete file from being identified correctly so we had to remove them. As stated earlier, this code was written to be used from a DLL. You can put it directly into your project, either way, you’ll use it the same.

private void ScanForPartials()
{
var targetPath ="C:\\SomePath\\";
if(Directory.Exists(TargetPath))
{
var fileList = Directory.GetFiles(TargetPath);
progressBar1.Maximum = fileList.Count();
var incomplete = 0;
foreach(var s in fileList)
{
var obj = newImageFile(s);
if(obj.FileType == ImageFileType.FileNotFound || obj.FileType == ImageFileType.NotRecognized) continue;
if(obj.FileComplete != false) continue;
incomplete++;
Console.Write(string.Format("{0}) InComplete {1}: {2}", incomplete, Enum.GetName(typeof(ImageFileType), obj.FileType), obj.FileName));
}
}
}

This is an example of how you can use this new class in your code. This example code scans through every file in a given directory and displays a list of incomplete files to the console. Notice that this example code will ignore any file format not specifically handled or recognized by the class code. To make this a complete program, simply place a call to this method inside your main event.