Unexpected Stripes In Bitmap

A

aaron.radich

I'm testing the creating of a 20x10 4bpp Indexed bitmap on the fly.
The bitmap has a 16 color palette, which I manipulate before writing a
byte array back to the bitmap. I'm setting most of the bytes in the
byte array to the color black and only 1 byte/pixel to the color
purple. What's strange is that the final bitmap saved to disk has
purple virticle stripes running through it. Does anyone have any idea
what might be going on? I've included the full source for a simple
application that demonstrates the problem. Thanks in advance!

Aaron


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
byte[] aByteBuffer = new byte[200];

System.Drawing.Bitmap bmpBuffer = new Bitmap(@"C:
\SongbookMaster\Win32\BitmapStreamTest\WindowsFormsApplication1\bin
\Debug\Image1.bmp");

ColorPalette cpPalette = bmpBuffer.Palette;
cpPalette.Entries[0] = Color.Purple;
cpPalette.Entries[1] = Color.SkyBlue;
cpPalette.Entries[2] = Color.Yellow;
cpPalette.Entries[3] = Color.White;
cpPalette.Entries[4] = Color.Red;
cpPalette.Entries[5] = Color.Brown;
cpPalette.Entries[6] = Color.Black;
cpPalette.Entries[7] = Color.Black;
cpPalette.Entries[8] = Color.Black;
cpPalette.Entries[9] = Color.Black;
cpPalette.Entries[10] = Color.Black;
cpPalette.Entries[11] = Color.Black;
cpPalette.Entries[12] = Color.Black;
cpPalette.Entries[13] = Color.Black;
cpPalette.Entries[14] = Color.Black;
cpPalette.Entries[15] = Color.Black;

for (int i = 0; i < 200; i++)
{
aByteBuffer = 6;
}

aByteBuffer[0] = 0;
aByteBuffer[1] = 1;
aByteBuffer[2] = 2;
aByteBuffer[3] = 3;
aByteBuffer[4] = 4;
aByteBuffer[5] = 5;

bmpBuffer = CopyDataToBitmap(ref aByteBuffer, cpPalette);

string sBMFilename = @"C:\Temp\Bitmaps\TestBitmap.bmp";
if (File.Exists(sBMFilename))
File.Delete(sBMFilename);
bmpBuffer.Save(sBMFilename);
}

private Bitmap CopyDataToBitmap(ref byte[] data, ColorPalette
cpPalette)
{
// here create the Bitmap to the know height, width and
format
//Bitmap bmp = new Bitmap(iSCREEN_WIDTH, iSCREEN_HEIGHT,
PixelFormat.Format32bppArgb);
Bitmap bmp = new Bitmap(20, 10,
PixelFormat.Format4bppIndexed);
bmp.Palette = cpPalette;

// create a BitmapData and Lock all pixels to be written
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0,
bmp.Width, bmp.Height),
ImageLockMode.WriteOnly,
bmp.PixelFormat);

// copy the data from the byte array into BitmapData.Scan0
int iBytes = bmpData.Stride * bmp.Height;
//Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
Marshal.Copy(data, 0, bmpData.Scan0, iBytes);

// unlock the pixels
bmp.UnlockBits(bmpData);
bmpData = null;
// return the bitmap
return bmp;
}

}
}
 
A

aaron.radich

I'm testing the creating of a 20x10 4bpp Indexed bitmap on the fly.
The bitmap has a 16 color palette, which I manipulate before writing a
byte array back to the bitmap.  I'm setting most of the bytes in the
byte array to the color black and only 1 byte/pixel to the color
purple.  What's strange is that the final bitmap saved to disk has
purple virticle stripes running through it.  Does anyone have any idea
what might be going on?

Did you read my previous message about making sure that the data in your  
byte[] is actually formatted correctly?  You had previously indicated that  
you were storing one palette index per byte, which for a 4bpp image is  
incorrect (and would cause striping as you describe).

Note that you haven't posted a concise-but-complete code sample.  In  
particular, it relies on data we surely don't have, and it's missing the  
entire Designer-created .cs file.  You can (and should) create a  
single-file project that is the result of merging your Program.cs,  
Form1.cs and Form1.Designer.cs files together, and then post that.  You 
should also make sure that whatever data is used to demonstrate the issue 
is generated programmatically, rather than relying on some bitmap file  
that exists only on your computer..

Pete



Sorry, below is the single project file with full source. I'm not
sure how to get around having the local bitmap file as that's how I'm
currently getting access to the 16 color palette. No constructor on
a ColorPalette. I'm still thinking on that.

I guess I need to do some more research on what you're referring to
with regard to the 4bpp causing stripping. What pixel format should I
use then if I need to have a 16 color palette and want to store a 0 to
15 in each byte of the byte array to represent the indexed color?

Aaron


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}

partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be
disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(26, 26);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler
(this.button1_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}

#endregion

private System.Windows.Forms.Button button1;
}

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
byte[] aByteBuffer = new byte[200];

System.Drawing.Bitmap bmpBuffer = new Bitmap(@"C:
\SongbookMaster\Win32\BitmapStreamTest\WindowsFormsApplication1\bin
\Debug\Image1.bmp");

ColorPalette cpPalette = bmpBuffer.Palette;
cpPalette.Entries[0] = Color.Purple;
cpPalette.Entries[1] = Color.SkyBlue;
cpPalette.Entries[2] = Color.Yellow;
cpPalette.Entries[3] = Color.White;
cpPalette.Entries[4] = Color.Red;
cpPalette.Entries[5] = Color.Brown;
cpPalette.Entries[6] = Color.Black;
cpPalette.Entries[7] = Color.Black;
cpPalette.Entries[8] = Color.Black;
cpPalette.Entries[9] = Color.Black;
cpPalette.Entries[10] = Color.Black;
cpPalette.Entries[11] = Color.Black;
cpPalette.Entries[12] = Color.Black;
cpPalette.Entries[13] = Color.Black;
cpPalette.Entries[14] = Color.Black;
cpPalette.Entries[15] = Color.Black;

for (int i = 0; i < 200; i++)
{
aByteBuffer = 6;
}

aByteBuffer[0] = 0;
aByteBuffer[1] = 1;
aByteBuffer[2] = 2;
aByteBuffer[3] = 3;
aByteBuffer[4] = 4;
aByteBuffer[5] = 5;

bmpBuffer = CopyDataToBitmap(ref aByteBuffer, cpPalette);

string sBMFilename = @"C:\Temp\Bitmaps\TestBitmap.bmp";
if (File.Exists(sBMFilename))
File.Delete(sBMFilename);
bmpBuffer.Save(sBMFilename);
}

private System.Drawing.Bitmap CopyDataToBitmap(ref byte[] data,
System.Drawing.Imaging.ColorPalette cpPalette)
{
// here create the Bitmap to the know height, width and
format
//Bitmap bmp = new Bitmap(iSCREEN_WIDTH, iSCREEN_HEIGHT,
PixelFormat.Format32bppArgb);
Bitmap bmp = new Bitmap(20, 10,
PixelFormat.Format4bppIndexed);
bmp.Palette = cpPalette;

// create a BitmapData and Lock all pixels to be written
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0,
bmp.Width, bmp.Height),
ImageLockMode.WriteOnly,
bmp.PixelFormat);

// copy the data from the byte array into BitmapData.Scan0
int iBytes = bmpData.Stride * bmp.Height;
//Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
Marshal.Copy(data, 0, bmpData.Scan0, iBytes);

// unlock the pixels
bmp.UnlockBits(bmpData);
bmpData = null;
// return the bitmap
return bmp;
}

}
}
 
A

aaron.radich

There was a recent thread discussing how to create a palette from  
scratch.  You can use Google to find it, but the gist is that you start 
with a Bitmap of the appropriate bit-depth, and then get the palette from 
that Bitmap.  You can then modify the palette as you desire.


If you want to store the index, one index (i.e. one pixel) per byte, then 
that's an 8-bit (i.e. "8bpp") bitmap, not a 4-bit bitmap.  Just because 
the data ranges only from 0 to 15, that doesn't automatically make it  
4-bits per pixel.  It's how the data is _stored_ that matters, not what 
the possible values are.

Conversely, if you really want a 4bpp bitmap, then you need to store two  
pixels of data in each byte, 4 bits for each pixel.

Pete

Thanks. I converted to using 8bpp and created the bitmap from scratch
by passing in the PixelFormat. Thanks for you help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top