I'm trying to create an 8-bit image with a solid background color. It seems like it should be pretty straight forward but the details on the file list it as 32-bit color depth. What am I missing?
public void CreateImage()
{
var bmpOut = new Bitmap(300, 300);
var g = Graphics.FromImage(bmpOut);
g.FillRectangle(new SolidBrush(Color.Gray), 0, 0, 300, 300);
var stream = new MemoryStream();
bmpOut.Save(stream, GetPngCodecInfo(), GetEncoderParameters());
bmpOut.Save(#"C:\image.png", GetPngCodecInfo(), GetEncoderParameters());
}
public EncoderParameters GetEncoderParameters()
{
var parameters = new EncoderParameters();
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8);
return parameters;
}
public ImageCodecInfo GetPngCodecInfo()
{
var encoders = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo codecInfo = null;
foreach (var imageCodecInfo in encoders)
{
if (imageCodecInfo.FormatID != ImageFormat.Png.Guid)
continue;
codecInfo = imageCodecInfo;
break;
}
return codecInfo;
}
Use this constructor to specify a pixel format : http://msdn.microsoft.com/en-us/library/3z132tat.aspx
Since you cannot create a Graphics from an indexed pixel format, you can only write raw pixels to a 8-bit image.
Bitmap bitmap = new Bitmap(32, 32, PixelFormat.Format8bppIndexed);
var bitmapData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.ReadWrite, bitmap.PixelFormat);
Random random=new Random();
byte[] buffer=new byte[bitmap.Width*bitmap.Height];
random.NextBytes(buffer);
Marshal.Copy(buffer,0,bitmapData.Scan0,buffer.Length);
bitmap.UnlockBits(bitmapData);
bitmap.Save("test.bmp",ImageFormat.Bmp);
You can either use such code on WinForms : http://www.codeproject.com/Articles/17162/Fast-Color-Depth-Change-for-Bitmaps
Or if you can reference this class from WPF it will be much easier :
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.formatconvertedbitmap(v=vs.85).aspx
You could also create the image at a higher bit rate and then convert it to 8 bits just before saving. This would allow you to use a Graphics context when creating the image. See this question for suggestions on how to convert to 8 bits:C# - How to convert an Image into an 8-bit color Image?
ImageExtensions.cs
using System.Runtime.InteropServices;
using System.Linq;
using System.Drawing.Imaging;
using System.Drawing;
using System;
public static partial class ImageExtensions {
public static ColorPalette ToGrayScale(this ColorPalette palette) {
var entries=palette.Entries;
for(var i=entries.Length; i-->0; entries[i]=entries[i].ToGrayScale())
;
return palette;
}
public static Color ToGrayScale(this Color color, double[] luminance=null) {
var list=(luminance??new[] { 0.2989, 0.5870, 0.1140 }).ToList();
var channel=new[] { color.R, color.G, color.B };
var c=(byte)Math.Round(list.Sum(x => x*channel[list.IndexOf(x)]));
return Color.FromArgb(c, c, c);
}
public static Bitmap To8bppIndexed(this Bitmap original) {
var rect=new Rectangle(Point.Empty, original.Size);
var pixelFormat=PixelFormat.Format8bppIndexed;
var destination=new Bitmap(rect.Width, rect.Height, pixelFormat);
using(var source=original.Clone(rect, PixelFormat.Format32bppArgb)) {
var destinationData=destination.LockBits(rect, ImageLockMode.WriteOnly, pixelFormat);
var sourceData=source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat);
var destinationSize=destinationData.Stride*destinationData.Height;
var destinationBuffer=new byte[destinationSize];
var sourceSize=sourceData.Stride*sourceData.Height;
var sourceBuffer=new byte[sourceSize];
Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, sourceSize);
source.UnlockBits(sourceData);
destination.Palette=destination.Palette.ToGrayScale();
var list=destination.Palette.Entries.ToList();
for(var y=destination.Height; y-->0; ) {
for(var x=destination.Width; x-->0; ) {
var pixelIndex=y*destination.Width+x;
var sourceIndex=4*pixelIndex;
var color=
Color.FromArgb(
sourceBuffer[0+sourceIndex],
sourceBuffer[1+sourceIndex],
sourceBuffer[2+sourceIndex],
sourceBuffer[3+sourceIndex]
).ToGrayScale();
destinationBuffer[pixelIndex]=(byte)list.IndexOf(color);
}
}
Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, destinationSize);
destination.UnlockBits(destinationData);
}
return destination;
}
}
Call bmpOut=bmpOut.To8bppIndexed(); before you it save to file.
Related
I load image from disc:
var img = Image.FromFile("foo");
var bmp = new Bitmap(img);
I wrote method to split image into pieces:
public static IEnumerable<Bitmap> VerticalSplit(this Bitmap src, int pixels)
{
var bmps = new List<Bitmap>();
for (int i = 0; i < src.Width; i+=pixels)
{
var dst = new Bitmap(pixels, src.Height);
using (var grD = Graphics.FromImage(dst))
{
grD.DrawImage(src, new Rectangle(i, 0, pixels, src.Height), new Rectangle(0,0,pixels,src.Height), GraphicsUnit.Pixel);
bmps.Add(dst);
}
}
return bmps;
}
And this is the usage:
var parts = bmp.VerticalSplit(10);
for (int i = 0; i < parts.Count(); i++)
{
parts[i].Save(#"output/" + i + ".jpg");
}
The problem is that every image except 1 is blank. Why does that happen?
See DrawImage, which has a signature of:
public void DrawImage (System.Drawing.Image image,
System.Drawing.Rectangle destRect, System.Drawing.Rectangle srcRect,
System.Drawing.GraphicsUnit srcUnit);
Note that the second parameter is "destRect", and the third parameter is "srcRect". Your code has the destination and source rectangles BACKWARDS.
Change:
grD.DrawImage(src, new Rectangle(i, 0, pixels, src.Height), new Rectangle(0,0,pixels,src.Height), GraphicsUnit.Pixel);
To:
grD.DrawImage(src, new Rectangle(0,0,pixels,src.Height), new Rectangle(i, 0, pixels, src.Height), GraphicsUnit.Pixel);
I would like to use Magick.NET
https://magick.codeplex.com/wikipage?title=Convert%20image&referringTitle=Documentation
in order to convert TIF to Black-and-White Monochrome TIF but manual does not explain it well.
I have tried this code but I am not sure of this approach is a correct one.
using (MagickImage image = new MagickImage("input.tif"))
{
image.CompressionMethod = CompressionMethod.Group4;
image.Write("output.tif");
}
Help needed. Thank you!
I found .NET code to do the same thing without any issues.
http://www.codeproject.com/Articles/15186/Bitonal-TIFF-Image-Converter-for-NET
private void convert_Click(object sender, EventArgs e)
{
// Load a bitmap from disk
Bitmap originalBitmap = new Bitmap(#"..\..\Bitonal-In.tif");
// Display image
originalImage.Image = originalBitmap;
// Convert bitmap to RGB format for drawing
Bitmap rgbBitmap = Converter.ConvertToRGB(originalBitmap);
// Convert image to bitonal for saving to file
Bitmap bitonalBitmap = Converter.ConvertToBitonal(rgbBitmap);
// Display converted image
convertedImage.Image = bitonalBitmap;
// Get an ImageCodecInfo object that represents the TIFF codec.
ImageCodecInfo imageCodecInfo = GetEncoderInfo("image/tiff");
System.Drawing.Imaging.Encoder encoder = System.Drawing.Imaging.Encoder.Compression;
EncoderParameters encoderParameters = new EncoderParameters(1);
// Save the bitmap as a TIFF file with group IV compression.
EncoderParameter encoderParameter = new EncoderParameter(encoder, (long)EncoderValue.CompressionCCITT4);
encoderParameters.Param[0] = encoderParameter;
bitonalBitmap.Save(#"..\..\Bitonal-Out.tif", imageCodecInfo, encoderParameters);
}
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace BitonalConverter
{
public static class Converter
{
public static Bitmap ConvertToRGB(Bitmap original)
{
Bitmap newImage = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
newImage.SetResolution(original.HorizontalResolution, original.VerticalResolution);
using (Graphics g = Graphics.FromImage(newImage))
{
g.DrawImageUnscaled(original, 0, 0);
}
return newImage;
}
public static Bitmap ConvertToBitonal(Bitmap original)
{
Bitmap source = null;
// If original bitmap is not already in 32 BPP, ARGB format, then convert
if (original.PixelFormat != PixelFormat.Format32bppArgb)
{
source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
source.SetResolution(original.HorizontalResolution, original.VerticalResolution);
using (Graphics g = Graphics.FromImage(source))
{
g.DrawImageUnscaled(original, 0, 0);
}
}
else
{
source = original;
}
// Lock source bitmap in memory
BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
// Copy image data to binary array
int imageSize = sourceData.Stride * sourceData.Height;
byte[] sourceBuffer = new byte[imageSize];
Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);
// Unlock source bitmap
source.UnlockBits(sourceData);
// Create destination bitmap
Bitmap destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed);
destination.SetResolution(original.HorizontalResolution, original.VerticalResolution);
// Lock destination bitmap in memory
BitmapData destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
// Create destination buffer
imageSize = destinationData.Stride * destinationData.Height;
byte[] destinationBuffer = new byte[imageSize];
int sourceIndex = 0;
int destinationIndex = 0;
int pixelTotal = 0;
byte destinationValue = 0;
int pixelValue = 128;
int height = source.Height;
int width = source.Width;
int threshold = 500;
// Iterate lines
for (int y = 0; y < height; y++)
{
sourceIndex = y * sourceData.Stride;
destinationIndex = y * destinationData.Stride;
destinationValue = 0;
pixelValue = 128;
// Iterate pixels
for (int x = 0; x < width; x++)
{
// Compute pixel brightness (i.e. total of Red, Green, and Blue values) - Thanks murx
// B G R
pixelTotal = sourceBuffer[sourceIndex] + sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2];
if (pixelTotal > threshold)
{
destinationValue += (byte)pixelValue;
}
if (pixelValue == 1)
{
destinationBuffer[destinationIndex] = destinationValue;
destinationIndex++;
destinationValue = 0;
pixelValue = 128;
}
else
{
pixelValue >>= 1;
}
sourceIndex += 4;
}
if (pixelValue != 128)
{
destinationBuffer[destinationIndex] = destinationValue;
}
}
// Copy binary image data to destination bitmap
Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);
// Unlock destination bitmap
destination.UnlockBits(destinationData);
// Dispose of source if not originally supplied bitmap
if (source != original)
{
source.Dispose();
}
// Return
return destination;
}
}
}
I have byte[] that store some image of unknown size. I need to resize this bitmap into 160 x 160 and bind to Wpf window.
Should i convert byte[] to Bitmap, resize, make BitmapSource from it and then use in wpf?
//result of this method binds to wpf
private static BitmapSource SetImage(byte[] dataBytes)
{
var picture = BitmapHelper.ByteToBitmap(dataBytes);
var resizedPicture = BitmapHelper.Resize(picture, 160, 160);
var bitmapSource = BitmapHelper.GetSourceFromBitmap(resizedPicture);
bitmapSource.Freeze();
return bitmapSource;
}
//BitmapHelper class:
public static Bitmap ByteToBitmap(byte[] byteArray)
{
using (var ms = new MemoryStream(byteArray))
{
var img = (Bitmap)Image.FromStream(ms);
return img;
}
}
internal static Bitmap Resize(Bitmap bitmap, int width, int height)
{
var newImage = new Bitmap(width, height);
using (var gr = Graphics.FromImage(newImage))
{
gr.SmoothingMode = SmoothingMode.HighQuality;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(bitmap, new Rectangle(0, 0, width, height));
}
return newImage;
}
internal static BitmapSource GetSourceFromBitmap(Bitmap source)
{
Contract.Requires(source != null);
var ip = source.GetHbitmap();
BitmapSource bs;
int result;
try
{
bs = Imaging.CreateBitmapSourceFromHBitmap(ip,
IntPtr.Zero, Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
finally
{
result = NativeMethods.DeleteObject(ip);
}
if (result == 0)
throw new InvalidOperationException("NativeMethods.DeleteObject returns 0 (operation failed)");
return bs;
}
internal static class NativeMethods
{
[DllImport("gdi32")]
static internal extern int DeleteObject(IntPtr o);
}
What is the fastest and common method for that case?
I'd suggest you to use the DecodePixelWidth and / or DecodePixelHeight properties of the BitmapImageclass (which inherits from ImageSource).
Take a look here:
BitmapSource GetImage(byte[] dataBytes)
{
using (MemoryStream stream = new MemoryStream(dataBytes))
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
// This is important: the image should be loaded on setting the StreamSource property, afterwards the stream will be closed
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.DecodePixelWidth = 160;
// Set this to 160 to get exactly 160x160 image
// Comment it out to retain original aspect ratio having the image width 160 and auto calculated image height
bi.DecodePixelHeight = 160;
bi.StreamSource = stream;
bi.EndInit();
return bi;
}
}
Using C# how can I resize a jpeg image? A code sample would be great.
I'm using this:
public static void ResizeJpg(string path, int nWidth, int nHeight)
{
using (var result = new Bitmap(nWidth, nHeight))
{
using (var input = new Bitmap(path))
{
using (Graphics g = Graphics.FromImage((System.Drawing.Image)result))
{
g.DrawImage(input, 0, 0, nWidth, nHeight);
}
}
var ici = ImageCodecInfo.GetImageEncoders().FirstOrDefault(ie => ie.MimeType == "image/jpeg");
var eps = new EncoderParameters(1);
eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
result.Save(path, ici, eps);
}
}
Good free resize filter and example code.
http://code.google.com/p/zrlabs-yael/
private void MakeResizedImage(string fromFile, string toFile, int maxWidth, int maxHeight)
{
int width;
int height;
using (System.Drawing.Image image = System.Drawing.Image.FromFile(fromFile))
{
DetermineResizeRatio(maxWidth, maxHeight, image.Width, image.Height, out width, out height);
using (System.Drawing.Image thumbnailImage = image.GetThumbnailImage(width, height, new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero))
{
if (image.Width < thumbnailImage.Width && image.Height < thumbnailImage.Height)
File.Copy(fromFile, toFile);
else
{
ImageCodecInfo ec = GetCodecInfo();
EncoderParameters parms = new EncoderParameters(1);
parms.Param[0] = new EncoderParameter(Encoder.Compression, 40);
ZRLabs.Yael.BasicFilters.ResizeFilter rf = new ZRLabs.Yael.BasicFilters.ResizeFilter();
//rf.KeepAspectRatio = true;
rf.Height = height;
rf.Width = width;
System.Drawing.Image img = rf.ExecuteFilter(System.Drawing.Image.FromFile(fromFile));
img.Save(toFile, ec, parms);
}
}
}
}
C# (or rather: the .NET framework) itself doesn't offer such capability, but it does offer you Bitmap from System.Drawing to easily access the raw pixel data of various picture formats. For the rest, see http://en.wikipedia.org/wiki/Image_scaling
Nice example.
public static Image ResizeImage(Image sourceImage, int maxWidth, int maxHeight)
{
// Determine which ratio is greater, the width or height, and use
// this to calculate the new width and height. Effectually constrains
// the proportions of the resized image to the proportions of the original.
double xRatio = (double)sourceImage.Width / maxWidth;
double yRatio = (double)sourceImage.Height / maxHeight;
double ratioToResizeImage = Math.Max(xRatio, yRatio);
int newWidth = (int)Math.Floor(sourceImage.Width / ratioToResizeImage);
int newHeight = (int)Math.Floor(sourceImage.Height / ratioToResizeImage);
// Create new image canvas -- use maxWidth and maxHeight in this function call if you wish
// to set the exact dimensions of the output image.
Bitmap newImage = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppArgb);
// Render the new image, using a graphic object
using (Graphics newGraphic = Graphics.FromImage(newImage))
{
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
newGraphic.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
// Set the background color to be transparent (can change this to any color)
newGraphic.Clear(Color.Transparent);
// Set the method of scaling to use -- HighQualityBicubic is said to have the best quality
newGraphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Apply the transformation onto the new graphic
Rectangle sourceDimensions = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);
Rectangle destinationDimensions = new Rectangle(0, 0, newWidth, newHeight);
newGraphic.DrawImage(sourceImage, destinationDimensions, sourceDimensions, GraphicsUnit.Pixel);
}
// Image has been modified by all the references to it's related graphic above. Return changes.
return newImage;
}
Source : http://mattmeisinger.com/resize-image-c-sharp
ImageMagick should be the best way. Easy and reliable.
using (var image = new MagickImage(imgfilebuf))
{
image.Resize(len, len);
image.Strip();
using MemoryStream ms = new MemoryStream();
image.Write(ms);
return ms.ToArray();
}
I need to convert bitonal (black and white) TIFF files into another format for display by a web browser, currently we're using JPGs, but the format isn't crucial. From reading around .NET doesn't seem to easily support writing bitonal images, so we're ending up with ~1MB files instead of ~100K ones. I'm considering using ImageMagick to do this, but ideally i'd like a solution which doesn't require this if possible.
Current code snippet (which also does some resizing on the image):
using (Image img = Image.FromFile(imageName))
{
using (Bitmap resized = new Bitmap(resizedWidth, resizedHeight)
{
using (Graphics g = Graphics.FromImage(resized))
{
g.DrawImage(img, new Rectangle(0, 0, resized.Width, resized.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel);
}
resized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
Is there any way to achieve this?
Thanks.
I believe the problem can be solved by checking that resized bitmap is of PixelFormat.Format1bppIndexed. If it's not, you should convert it to 1bpp bitmap and after that you can save it as black and white png without problems.
In other words, you should use following code instead of resized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Jpeg);
if (resized.PixelFormat != PixelFormat.Format1bppIndexed)
{
using (Bitmap bmp = convertToBitonal(resized))
bmp.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Png);
}
else
{
resized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Png);
}
I use following code for convertToBitonal :
private static Bitmap convertToBitonal(Bitmap original)
{
int sourceStride;
byte[] sourceBuffer = extractBytes(original, out sourceStride);
// Create destination bitmap
Bitmap destination = new Bitmap(original.Width, original.Height,
PixelFormat.Format1bppIndexed);
destination.SetResolution(original.HorizontalResolution, original.VerticalResolution);
// Lock destination bitmap in memory
BitmapData destinationData = destination.LockBits(
new Rectangle(0, 0, destination.Width, destination.Height),
ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
// Create buffer for destination bitmap bits
int imageSize = destinationData.Stride * destinationData.Height;
byte[] destinationBuffer = new byte[imageSize];
int sourceIndex = 0;
int destinationIndex = 0;
int pixelTotal = 0;
byte destinationValue = 0;
int pixelValue = 128;
int height = destination.Height;
int width = destination.Width;
int threshold = 500;
for (int y = 0; y < height; y++)
{
sourceIndex = y * sourceStride;
destinationIndex = y * destinationData.Stride;
destinationValue = 0;
pixelValue = 128;
for (int x = 0; x < width; x++)
{
// Compute pixel brightness (i.e. total of Red, Green, and Blue values)
pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] +
sourceBuffer[sourceIndex + 3];
if (pixelTotal > threshold)
destinationValue += (byte)pixelValue;
if (pixelValue == 1)
{
destinationBuffer[destinationIndex] = destinationValue;
destinationIndex++;
destinationValue = 0;
pixelValue = 128;
}
else
{
pixelValue >>= 1;
}
sourceIndex += 4;
}
if (pixelValue != 128)
destinationBuffer[destinationIndex] = destinationValue;
}
Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);
destination.UnlockBits(destinationData);
return destination;
}
private static byte[] extractBytes(Bitmap original, out int stride)
{
Bitmap source = null;
try
{
// If original bitmap is not already in 32 BPP, ARGB format, then convert
if (original.PixelFormat != PixelFormat.Format32bppArgb)
{
source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
source.SetResolution(original.HorizontalResolution, original.VerticalResolution);
using (Graphics g = Graphics.FromImage(source))
{
g.DrawImageUnscaled(original, 0, 0);
}
}
else
{
source = original;
}
// Lock source bitmap in memory
BitmapData sourceData = source.LockBits(
new Rectangle(0, 0, source.Width, source.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
// Copy image data to binary array
int imageSize = sourceData.Stride * sourceData.Height;
byte[] sourceBuffer = new byte[imageSize];
Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);
// Unlock source bitmap
source.UnlockBits(sourceData);
stride = sourceData.Stride;
return sourceBuffer;
}
finally
{
if (source != original)
source.Dispose();
}
}
Have you tried saving using the Image.Save overload with Encoder parameters?
Like the Encoder.ColorDepth Parameter?
Trying jaroslav's suggestion for color depth doesn't work:
static void Main(string[] args)
{
var list = ImageCodecInfo.GetImageDecoders();
var jpegEncoder = list[1]; // i know this is the jpeg encoder by inspection
Bitmap bitmap = new Bitmap(500, 500);
Graphics g = Graphics.FromImage(bitmap);
g.DrawRectangle(new Pen(Color.Red), 10, 10, 300, 300);
var encoderParams = new EncoderParameters();
encoderParams.Param[0] = new EncoderParameter(Encoder.ColorDepth, 2);
bitmap.Save(#"c:\newbitmap.jpeg", jpegEncoder, encoderParams);
}
The jpeg is still a full color jpeg.
I don't think there is any support for grayscale jpeg in gdi plus. Have you tried looking in windows imaging component?
http://www.microsoft.com/downloads/details.aspx?FamilyID=8e011506-6307-445b-b950-215def45ddd8&displaylang=en
code example: http://www.codeproject.com/KB/GDI-plus/windows_imaging.aspx
wikipedia: http://en.wikipedia.org/wiki/Windows_Imaging_Component
This is an old thread. However, I'll add my 2 cents.
I use AForge.Net libraries (open source)
use these dlls. Aforge.dll, AForge.Imaging.dll
using AForge.Imaging.Filters;
private void ConvertBitmap()
{
markedBitmap = Grayscale.CommonAlgorithms.RMY.Apply(markedBitmap);
ApplyFilter(new FloydSteinbergDithering());
}
private void ApplyFilter(IFilter filter)
{
// apply filter
convertedBitmap = filter.Apply(markedBitmap);
}
Have you tried PNG with 1 bit color depth?
To achieve a size similar to a CCITT4 TIFF, I believe your image needs to use a 1-bit indexed pallette.
However, you can't use the Graphics object in .NET to draw on an indexed image.
You will probably have to use LockBits to manipulate each pixel.
See Bob Powell's excellent article.