Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Convert B&W image to 1Bpp

Status
Not open for further replies.

Leonos

Programmer
Sep 17, 2003
32
NL
I have made a converter that converts a colorred image into a black and white image.
This converter also fakes grays by filling these with black/white/black/white etc.

This produces a very decent black and white picture, but it is in 24bpp.

Now I want to fax that image and need to convert it to 1bpp.

On the internet I see a lot of 'scan' 'stripe' solutions, but al of these give me a (much) poorer result image.

Isn't it possible to do this pixel by pixel ?
 
Hi there,
I found a way of doing this.

Here the code:

private void ResaveTiffBlackWhite(FileStream fs, string destPath)
{
// FileStream fs = File.Open(sourcePath, FileMode.Open, FileAccess.Read);
Bitmap srcBmp = new Bitmap(fs);// (Bitmap)Bitmap.FromStream(fs);

int totalPages = (int)(srcBmp.GetFrameCount(FrameDimension.Page));

ImageCodecInfo ici = GetTiffCodec();
EncoderParameters ep = GetBWEncoderParams();

Bitmap destFile = null;
int currentPage = 0;
for (currentPage = 0; currentPage < totalPages; currentPage++)
{
srcBmp.SelectActiveFrame(FrameDimension.Page, currentPage);
Bitmap tempBmp = GetRGBPage(srcBmp, 1652, 2352);
Bitmap destPage = new Bitmap(tempBmp.Width, tempBmp.Height, PixelFormat.Format1bppIndexed);//.Format16bppGrayScale);
destPage.SetResolution(200, 200);

destPage = Get1BppImage(tempBmp);

if (currentPage == 0)
{
if (destPage.Width > destPage.Height) { destPage.RotateFlip(RotateFlipType.Rotate90FlipNone); }

destFile = destPage;
destFile.Save(destPath, ici, ep);
}
else
{
if (destPage.Width > destPage.Height) { destPage.RotateFlip(RotateFlipType.Rotate90FlipNone); }
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, (long)(EncoderValue.FrameDimensionPage));
destFile.SaveAdd(destPage, ep);
}

if (currentPage == (int)(srcBmp.GetFrameCount(FrameDimension.Page) - 1))
{
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, (long)(EncoderValue.Flush));
destFile.SaveAdd(ep);
}
}
destFile.Dispose();
fs.Close();
}

private System.Drawing.Imaging.ImageCodecInfo GetTiffCodec()
{
foreach (ImageCodecInfo ici in ImageCodecInfo.GetImageEncoders())
{
if (ici.MimeType == "image/tiff")
{
return ici;
}
}
return null;
}

private System.Drawing.Imaging.EncoderParameters GetBWEncoderParams()
{
EncoderParameters ep = new EncoderParameters(2);

ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, Convert.ToInt32(EncoderValue.MultiFrame));
ep.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, Convert.ToInt32(EncoderValue.CompressionCCITT3));
// ep.Param[2] = new EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 1L);

return ep;
}

private Bitmap GetRGBPage(Bitmap srcBmp, int newWidth, int newHeight)
{
if (srcBmp.Width > srcBmp.Height)
{
int tempHeight = newHeight;
newHeight = newWidth;
newWidth = tempHeight;
}
Bitmap tempBmp = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppArgb);//((int)(resizeRatio * srcBmp.Width), (int)(resizeRatio * srcBmp.Height), PixelFormat.Format32bppArgb);
tempBmp.SetResolution(200, 200);
Graphics g = Graphics.FromImage(tempBmp);
g.DrawImage(srcBmp, new Rectangle(0, 0, tempBmp.Width, tempBmp.Height), 0, 0, srcBmp.Width, srcBmp.Height, GraphicsUnit.Pixel);
g.Dispose();

return tempBmp;
}

private Bitmap Get1BppImage(Bitmap srcBitmap)
{
//Be sure to have / create a Format32bppPArgb bitmap and resize it
if (srcBitmap.PixelFormat != PixelFormat.Format32bppPArgb)
{
Bitmap temp = new Bitmap(srcBitmap.Width, srcBitmap.Height, PixelFormat.Format32bppPArgb);
temp.SetResolution(200, 200);
Graphics g = Graphics.FromImage(temp);
g.DrawImage(srcBitmap, new Rectangle(0, 0, temp.Width, temp.Height), 0, 0, srcBitmap.Width, srcBitmap.Height, GraphicsUnit.Pixel);
srcBitmap.Dispose();
g.Dispose();
srcBitmap = temp;
}

//lock the bits of the original bitmap
BitmapData bmdo = srcBitmap.LockBits(new Rectangle(0, 0, srcBitmap.Width, srcBitmap.Height), ImageLockMode.ReadOnly, srcBitmap.PixelFormat);

//and the new 1bpp bitmap
Bitmap destBitmap = new Bitmap(srcBitmap.Width, srcBitmap.Height, PixelFormat.Format1bppIndexed);
BitmapData bmdn = destBitmap.LockBits(new Rectangle(0, 0, destBitmap.Width, destBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
destBitmap.SetResolution(200, 200); //I want a resolution of 200dpi x 200dpi

//scan through the pixels Y by X
int x, y;

for (x = 0; x < srcBitmap.Width; x++)
{
for (y = 0; y < srcBitmap.Height; y++)
{
//generate the address of the colour pixel

int index = y * bmdo.Stride + (x * 4);
float myBrigthness = Color.FromArgb(Marshal.ReadByte(bmdo.Scan0, index + 2),
Marshal.ReadByte(bmdo.Scan0, index + 1),
Marshal.ReadByte(bmdo.Scan0, index)).GetBrightness();

//check its brightness and if between 0.33f and 0.67f create fake gray by alternating black and white (note that you have to cross depending on x-y position)
if (myBrigthness < 0.33f)
{
//Black thus do nothing
}
else if (myBrigthness < 0.67f)
{
if ((x + (y % 2)) % 2 == 1)
{
//Black thus do nothing
}
else
{
//White
this.SetIndexedPixel(x, y, bmdn, true); //set it if its bright.
}
}
else
{
//White
this.SetIndexedPixel(x, y, bmdn, true); //set it if its bright.
}
}
}

//tidy up
destBitmap.UnlockBits(bmdn);
srcBitmap.UnlockBits(bmdo);

return destBitmap;
}

protected void SetIndexedPixel(int x, int y, BitmapData bmd, bool pixel)
{
int index = y * bmd.Stride + (x >> 3);
byte p = Marshal.ReadByte(bmd.Scan0, index);
byte mask = (byte)(0x80 >> (x & 0x7));
if (pixel)
p |= mask;
else
p &= (byte)(mask ^ 0xff);
Marshal.WriteByte(bmd.Scan0, index, p);
}
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top