I want to remove grayness from the picture in pictureBox1, as in the first photo below. The second photo shows the formulas that can be used to do this. I wrote an approximate code, but the compiler throws an error, that variables red1, green1 and blue1 cannot be written to Color newPixel due to type incompatibility. Please help me fixing my code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void pictureBox1_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = "Відкрити зображення";
dlg.Filter = "jpg files (*.jpg)|*.jpg|All filles (*.*)|*.*";
if (dlg.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = new Bitmap(dlg.OpenFile());
pictureBox1.Height = pictureBox1.Image.Height;
pictureBox1.Width = pictureBox1.Image.Width;
}
dlg.Dispose();
label1.Visible = false;
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap input = new Bitmap(pictureBox1.Image);
Bitmap output = new Bitmap(input.Width, input.Height);
int[] red = new int[256];
int[] green = new int[256];
int[] blue = new int[256];
for (int x = 0; x < input.Width; x++)
{
for (int y = 0; y < input.Height; y++)
{
Color pixel = ((Bitmap)pictureBox1.Image).GetPixel(x, y);
red[pixel.R]++;
green[pixel.G]++;
blue[pixel.B]++;
double Ri = red.Average();
double Gi = green.Average();
double Bi = blue.Average();
double Avg = (Ri+Bi+Gi)/3;
double red1 = red (Avg/Ri);
double green1 = green(Avg / Gi);
double blue1 = blue(Avg / Bi);
Color newPixel = ((Color)red1| (Color)green1 | (Color)blue1);
output.SetPixel(x, y, Color.((int)newPixel));
}
}
pictureBox2.Image = output;
}
}
}
You should use Color.FromArgb() to create the new color. However, this method expects 3 int as input and not double, so you need to convert your doubles to integers.
Simple type cast - (int)someDouble
This solution will simply remove any decimals from the double value (1.9 => 1):
double red1 = 123.45;
double green1 = 12.345;
double blue1 = 234.56;
Color newPixel = Color.FromArgb((int)red1, (int)green1, (int)blue1);
// R=123, G=12, B=234
Math.Round(someDouble)
This solution will round the double value to the nearest integer (1.5 => 2 and 1.49 => 1):
int red1 = (int)Math.Round(123.45);
int green1 = (int)Math.Round(12.345);
int blue1 = (int)Math.Round(234.56);
Color newPixel = Color.FromArgb(red1, green1, blue1);
// R=123, G=12, B=235
You misinterpreted the formula. N in the formula specifies the total number of the pixels in the image. The overlined letters means the average channel value over the image. These variable should be the type of double. I called them redAverage, greenAverage and blueAverage, respectively. And as you
already know, Avg is the average of these variables. Finally, R', G', B' are the new channel values calculated using the old values.
using System.Drawing.Imaging;
namespace Convert2Gray
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private Bitmap m_inputImage;
private Bitmap m_outputImage;
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
m_inputImage = (Bitmap)Image.FromFile("sample.png");
m_outputImage = new Bitmap(m_inputImage.Width, m_inputImage.Height, m_inputImage.PixelFormat);
pictureBox1.Image = m_inputImage;
pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
DoConversion();
pictureBox2.Image = m_outputImage;
pictureBox2.SizeMode = PictureBoxSizeMode.AutoSize;
}
private unsafe void DoConversion()
{
BitmapData inputBitmapData = m_inputImage.LockBits(new Rectangle(0, 0, m_inputImage.Width, m_inputImage.Height), ImageLockMode.ReadWrite, m_inputImage.PixelFormat);
BitmapData outputBitmapData = m_outputImage.LockBits(new Rectangle(0, 0, m_outputImage.Width, m_outputImage.Height), ImageLockMode.ReadWrite, m_outputImage.PixelFormat);
byte* inputScan0 = (byte*)inputBitmapData.Scan0;
byte* outputScan0 = (byte*)outputBitmapData.Scan0;
int inputStride = inputBitmapData.Stride;
int outputStride = outputBitmapData.Stride;
int bytesPerPixel = Image.GetPixelFormatSize(m_inputImage.PixelFormat) / 8;
double redAverage = 0.0;
double greenAverage = 0.0;
double blueAverage = 0.0;
double average = 0.0;
int pixelCount = m_inputImage.Width * m_inputImage.Height;
for (int y = 0; y < m_inputImage.Height; y++)
{
byte* inputCurrentRow = inputScan0 + y * inputStride;
byte* outputCurrentRow = outputScan0 + y * outputStride;
for (int x = 0; x < m_inputImage.Width; x++)
{
ColorBgr* inputColor = (ColorBgr*)(inputCurrentRow + x * bytesPerPixel);
redAverage += inputColor->R;
greenAverage += inputColor->G;
blueAverage += inputColor->B;
}
}
redAverage /= pixelCount;
greenAverage /= pixelCount;
blueAverage /= pixelCount;
average = (redAverage + greenAverage + blueAverage) / 3;
for (int y = 0; y < m_inputImage.Height; y++)
{
byte* inputCurrentRow = inputScan0 + y * inputStride;
byte* outputCurrentRow = outputScan0 + y * outputStride;
for (int x = 0; x < m_inputImage.Width; x++)
{
ColorBgr* inputColor = (ColorBgr*)(inputCurrentRow + x * bytesPerPixel);
ColorBgr* outputColor = (ColorBgr*)(outputCurrentRow + x * bytesPerPixel);
outputColor->R = (byte)(inputColor->R * average / redAverage);
outputColor->G = (byte)(inputColor->G * average / greenAverage);
outputColor->B = (byte)(inputColor->B * average / blueAverage);
}
}
m_inputImage.UnlockBits(inputBitmapData);
m_outputImage.UnlockBits(outputBitmapData);
}
private struct ColorBgr : IEquatable<ColorBgr>
{
public byte B;
public byte G;
public byte R;
public ColorBgr(byte b, byte g, byte r)
{
B = b;
G = g;
R = r;
}
public static bool operator ==(ColorBgr left, ColorBgr right)
{
return left.Equals(right);
}
public static bool operator !=(ColorBgr left, ColorBgr right)
{
return !(left == right);
}
public bool Equals(ColorBgr other)
{
return this.B == other.B && this.G == other.G && this.R == other.R;
}
public override bool Equals(object? obj)
{
if (obj is ColorBgr)
return Equals((ColorBgr)obj);
return false;
}
public override int GetHashCode()
{
return new byte[] { B, G, R }.GetHashCode();
}
}
}
}
Related
I'm trying to create some simple graphics ("plasma" effect) with C# and Winforms.
I have two classes in my code, (main)Form1 and Plasmadraw.
In Plasmadraw I have following setup:
class Plasmadraw
{
int y;
int x;
double i;
double pii = 3.1415;
public void Draw(Graphics gfx, int addition)
{
for (int i = 0; i < 23040; i++)
{
x = x + 10;
if (x == 1920)
{
x = 0;
y = y + 10;
}
if (y == 1200)
{
y = 0;
}
double v = Math.Sin((x * 0.5) + i * 0.001 * addition);
double c = v * pii;
double d = c + (2 * pii / 3);
double f = c + (6 * pii / 3);
double r = 255 * Math.Abs(Math.Sin(c));
double g = 255 * Math.Abs(Math.Sin(d));
double b = 255 * Math.Abs(Math.Sin(f));
int r1 = (int)r;
int g1 = (int)g;
int b1 = (int)b;
Color e = Color.FromArgb(r1, g1, b1);
SolidBrush brush = new SolidBrush(e);
Rectangle rect = new Rectangle(x, y, 10, 10);
gfx.FillRectangle(brush, rect);
}
}
}
and then in Form1 I have Paint event:
private void Form1_Paint(object sender, PaintEventArgs e)
{
Plasmadraw plasmaeffect = new Plasmadraw();
for (int a = 0; a < 30; a++)
{
plasmaeffect.Draw(e.Graphics, a);
Invalidate();
}
Is this somehow completely wrong way to build the logic ? I've managed to create some graphics effects (moving sprites etc.) by creating a list and then running through the list with Foreach in Paint event (& Invalidate()). However, I'd like to learn some new way to do things, rather than copying the old way.
I'm trying to make this class for processing images, and I wanted it to have a Bitmap field, and a constructor that would allow me to give to path to the bitmap so other methods could use that bitmap. So I wanted it to be able to do this:
ImageProcessing image = new ImageProcessing("D:\\image.bmp");
int time_of_processing = image.grayscale();
image.SaveTo("D:\\image2.bmp");
And so this is my code:
public class ImageProcessing
{
Bitmap image;
public ImageProcessing(string path)
{
image = new Bitmap(path);
}
public int Grayscale()
{
Stopwatch time = new Stopwatch();
time.Start();
for (int x = 0; x < image.Width; x++)
{
for (int y = 0; y < image.Height; y++)
{
Color pixelColor = image.GetPixel(x, y);
int grayScale = (int)((pixelColor.R * 0.21) + (pixelColor.G * 0.72) + (pixelColor.B * 0.07));
Color newColor = Color.FromArgb(grayScale, grayScale, grayScale);
image.SetPixel(x, y, newColor);
}
}
time.Stop();
TimeSpan ts = time.Elapsed;
int milliseconds = ts.Milliseconds + (ts.Seconds * 1000);
return milliseconds;
}
public void SaveTo(string path)
{
image.Save(path);
}
}
And when i have this, Visual Studio tells me that image will always be null. How should the constructor look for it to work?
Add the namespace to the ImageProcessing class when you use it to make sure its always using the correct class. The following code (which is mostly just the original code) has been tested and works (it grayscales the image listed).
namespace WindowsFormsApplication10
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
string path1 = #"C:\work\test.bmp";
string path2 = #"C:\work\test2.bmp";
WindowsFormsApplication10.ImageProcessing image = new WindowsFormsApplication10.ImageProcessing(path1);
int time_of_processing = image.Grayscale();
image.SaveTo(path2);
}
}
public class ImageProcessing
{
Bitmap image;
public ImageProcessing(string path)
{
image = new Bitmap(path);
}
public int Grayscale()
{
Stopwatch time = new Stopwatch();
time.Start();
for (int x = 0; x < image.Width; x++)
{
for (int y = 0; y < image.Height; y++)
{
Color pixelColor = image.GetPixel(x, y);
int grayScale = (int)((pixelColor.R * 0.21) + (pixelColor.G * 0.72) + (pixelColor.B * 0.07));
Color newColor = Color.FromArgb(grayScale, grayScale, grayScale);
image.SetPixel(x, y, newColor);
}
}
time.Stop();
TimeSpan ts = time.Elapsed;
int milliseconds = ts.Milliseconds + (ts.Seconds * 1000);
return milliseconds;
}
public void SaveTo(string path)
{
image.Save(path);
}
}
}
I am new to C# and graphing world. I am trying to plot serial data coming from Arduino as double datatype on ZedGraph in C#. I am unable to plot it. The graph is appearing with only the scale Y axis scale setting itself to the output value but nothing else. I shall be grateful for your help!! Thanks. Below is my code
PS: I put a message box to see the output and it is showing the correct output from the Arduino.
using System;
using System.Drawing;
using System.Windows.Forms;
using ZedGraph;
using System.IO.Ports;
namespace WindowsFormsApplication6
{
public partial class Form1 : Form
{
static string indata;
double x;
double d;
public Form1()
{
InitializeComponent();
PlotSerial();
// DrawGraph();
}
private void PlotSerial()
{
SerialPort sprt;
sprt = new SerialPort("COM4");
sprt.BaudRate = 115200;
try
{
sprt.Open();
}
catch (Exception)
{
MessageBox.Show("Check port");
}
// initializing zed graph
GraphPane pane = zedGraph.GraphPane;
PointPairList list2 = new PointPairList();
pane.YAxisList.Clear();
//X-Axis Settings
pane.XAxis.Scale.MinorStep = 1;
pane.XAxis.Scale.MajorStep = 5;
XDate time = new XDate(DateTime.Now.ToOADate());
pane.XAxis.Type = AxisType.Date;
pane.XAxis.Scale.Format = "ss";
pane.XAxis.Scale.Min = new XDate(DateTime.Now);
pane.XAxis.Scale.Max = new XDate(DateTime.Now.AddSeconds(25));
pane.XAxis.Scale.MinorUnit = DateUnit.Second;
pane.XAxis.Scale.MajorUnit = DateUnit.Second;
indata = sprt.ReadLine();
MessageBox.Show(indata);
bool result = Double.TryParse(indata, out d);
// double xmin = -50;
//double xmax = 50;
//for x = 0 To 36
//for (double x = xmin; x <= xmax; x += 1)
//for (int i = 1; i < 20; i++)
{
list2.Add(x, d);
}
Scale xScale1 = zedGraph.MasterPane.PaneList[0].XAxis.Scale;
if (time.XLDate > xScale1.Max)
{
xScale1.Max = (XDate)(DateTime.Now.AddSeconds(1));
xScale1.Min = (XDate)(DateTime.Now.AddSeconds(-40));
}
/*
// byte[] buffer = new byte[20];
indata = (byte)sprt.ReadByte();
//MessageBox.Show(indata);
//double xmin = -2;
//double xmax = 2;
// for (= xmin; x <= xmax; x +=1)
list2.Add(x, indata);
*/
pane.XAxis.Title.Text = "X Axis";
int axis2 = pane.AddYAxis("Y Axis");
LineItem myCurve2 = pane.AddCurve("Serialport_Curve", list2, Color.Blue, SymbolType.Diamond);
myCurve2.YAxisIndex = axis2;
pane.YAxisList[axis2].Title.FontSpec.FontColor = Color.Black;
zedGraph.AxisChange();
zedGraph.Invalidate();
}
private double f1(double x)
{
if (x == 0)
{
return 1;
}
return Math.Sin(x) / x;
}
private double f2(double x)
{
if (x == 0)
{
return 1;
}
return 10 * Math.Sin(x * 0.5) / x;
}
private double f3(double x)
{
if (x == 0)
{
return 1;
}
return 0.1 * Math.Sin(x * 2) / x;
}
}
}
This is the code .
But it's not coloring the bmp4 in yellow.
Maybe i did something wrong with the test variable and bmp4 variable and the CreateNonIndexedImage method ?
Tried also to save the bmp4 but it's not working.
In form1 when the operation end i'm saving the bitmap like this:
CloudEnteringAlert.test.Save(#"c:\temp\yellowbmpcolor.jpg");
But the area that supposed to be in yellow is not it's justl ike the original image.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.IO;
using DannyGeneral;
using System.Reflection;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace mws
{
public static class CloudEnteringAlert
{
private static PointF point1;
private static PointF point2;
public static float redlinerectx1= 0;
public static float redlinerecty1 = 0;
public static float redlinerectx = 0;
public static float redlinerecty = 0;
private static Bitmap bm;
private static Bitmap bmp2 = new Bitmap(#"C:\Temp\New folder (17)\radar001486.GIF");
public static Bitmap test = new Bitmap(#"D:\MyWeatherStation-Images-And-Icons\radar090.PNG");
public static Bitmap bmp4 = CreateNonIndexedImage(test);
static BitmapData b1 = bmp4.LockBits(new System.Drawing.Rectangle(0, 0, bmp4.Width, bmp4.Height),
System.Drawing.Imaging.ImageLockMode.ReadWrite,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
static int stride = b1.Stride;
static int k1, x1, y1;
static float fx, fy;
static System.IntPtr Scan0 = b1.Scan0;
public static List<string> pointscoordinates = new List<string>();
public static float radius = 2.0f;
private static Label lbl1 = new Label();
public static bool cloudsfound;
// blinking colors: yellow, red, yellow, transparent, repeat...
public static Brush[] cloudColors = new[] { Brushes.Yellow, Brushes.Transparent };
// current color index
public static int cloudColorIndex = 0;
public static List<PointF> AddDistanceToPoints = new List<PointF>();
public static List<PointF> MovingPoints = new List<PointF>();
public static List<PointF> PointsFloat = new List<PointF>();
public static List<Point> PointsInt;
public static List<PointF> pointtocolor = new List<PointF>();
public static List<PointF> extendedPoints = new List<PointF>();
public static Bitmap newbitmap;
private static List<PointF> clouds1;
public static List<PointF> clouds;
public static List<PointF> cloudsG = new List<PointF>();
public static List<PointF> cloudsY;
public static List<PointF> cloudsR;
private static Bitmap bmp3;
private static int tolerancenumeric = 0;
private static double[] treshhold_array = { 100, 50, 40, 30, 24, 18, 13, 9, 6, 4, 2, 1.2, 0.7, 0.2, 0.1 };
static List<float> LoadPoints_X = new List<float>();
static List<float> LoadPoints_Y = new List<float>();
static List<float> points_X = new List<float>();
static List<float> points_Y = new List<float>();
static string path;
static string file;
static List<PointF> points;
public static Bitmap CreateNonIndexedImage(Image src)
{
Bitmap newBmp = new Bitmap(src.Width, src.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics gfx = Graphics.FromImage(newBmp))
{
gfx.DrawImage(src, 0, 0);
}
return newBmp;
}
static CloudEnteringAlert()
{
points = new List<PointF>();
cloudsfound = false;
}
public static void Paint(Graphics e, double currentFactor, float kilometers)
{
Pen myPen = new Pen(Brushes.Red, 2);
float x, y ,width, height;
float distance = kilometers / (float)1.09;//289617486; // One pixel distance is 1.09 kilometer.
if (points == null)
{
return;
}
redlinerectx = MovingPoints[0].X;
redlinerecty = MovingPoints[0].Y;
if (clouds != null)
{
y = PointsInt.Min(p => p.Y);
PointF pointsIntMin = PointsInt.First(p => p.Y == y); //point with minimum Y in PointsInt list
y = PointsInt.Max(p => p.Y);
PointF pointsIntMax = PointsInt.First(p => p.Y == y); //point with maximum Y in PointsInt list
y = MovingPoints.Min(p => p.Y);
PointF movingPointsMin = MovingPoints.First(p => p.Y == y); //point with minimum Y in MovingPoints list
y = MovingPoints.Max(p => p.Y);
PointF movingPointsMax = PointsInt.First(p => p.Y == y); //point with minimum Y in MovingPoints list
x = pointsIntMin.X * (float)currentFactor;
y = pointsIntMin.Y * (float)currentFactor;
width = movingPointsMin.X + distance - x;
height = (pointsIntMax.Y - pointsIntMin.Y) * (float)currentFactor;
if (clouds != null)
{
e.DrawRectangle(myPen, (int)x, (int)y, (int)width, (int)height);
}
myPen.Dispose();
try
{
unsafe
{
byte* p;
for (k1 = 0; k1 < pointtocolor.Count; k1++)
{
//set pointer to the beggining
p = (byte*)(void*)Scan0;
fx = pointtocolor[k1].X * (float)currentFactor;
fy = pointtocolor[k1].Y * (float)currentFactor;
//check if point is inside bmp
if ((int)fx >= bmp.Width || (int)fy >= bmp.Height)
{
continue;
}
//Add offset where the point is. The formula: position = Y * stride + X * 4
x = (int)(fy * (float)stride);
y = (int)(fx * 4F);
p += (x1 + y1);
//set yellow color
p[1] = p[2] = (byte)255;
p[0] = (byte)0;
p[3] = (byte)255;
}
}
bmp.UnlockBits(b1);
}
catch
{
string t = "err";
}
}
}
EDIT
It is working but the color is not the yellow i need:
This is what i get:
And when i used with SetPixel this is what i got and what i want to get now too:
Draw individual pixels from list with yellow color on bmp Bitmap:
BitmapData b1 = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadWrite,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
int stride = b1.Stride;
int k, x, y;
float fx, fy;
System.IntPtr Scan0 = b1.Scan0;
unsafe
{
byte* p;
for (k = 0; k < pointtocolor.Count; k++)
{
//set pointer to the beggining
p = (byte*)(void*)Scan0;
fx = pointtocolor[k].X * (float)currentFactor;
fy = pointtocolor[k].Y * (float)currentFactor;
//check if point is inside bmp
if( (int)fx >= bmp.Width || (int)fy >= bmp.Height)
{
continue;
}
//Add offset where the point is. The formula: position = Y * stride + X * 4
x = (int)fy * stride;
y = (int)fx * 4;
p += ( x + y );
//set yellow color
p[1] = p[2] = (byte)255;
p[0] = (byte)0;
p[3] = (byte)255;
}
}
bmp.UnlockBits(b1);
I'm looking for a fast, professionally looking and customizable waveform display component in C#.
I'm wanting to display mainly real-time audio waveforms (fast!) in both time and frequency domain. I would like the ability to zoom, change axis settings, display multiple channels, customize the feel and colors etc...
Anybody knows of anything, whether commercial or not?
Thank you!
Diego
I bumped into a code project awhile ago that was doing this.
Check out http://www.codeproject.com/KB/miscctrl/GraphComponents.aspx it may be what you are looking for to do real-time graphing in .net
as far as i know, national instrument has some cool control, but it's not free.
http://sine.ni.com/psp/app/doc/p/id/psp-317
free ones:
http://www.codeproject.com/KB/audio-video/wavecontrol.aspx
Based on Illaya's code:
public void CreateWaveForm(string audioFilePath, string audioWaveFormFilePath)
{
try
{
int bytesPerSample = 0;
using (NAudio.Wave.Mp3FileReader reader = new NAudio.Wave.Mp3FileReader(audioFilePath, wf => new NAudio.FileFormats.Mp3.DmoMp3FrameDecompressor(wf)))
{
using (NAudio.Wave.WaveChannel32 channelStream = new NAudio.Wave.WaveChannel32(reader))
{
bytesPerSample = (reader.WaveFormat.BitsPerSample / 8) * channelStream.WaveFormat.Channels;
//Give a size to the bitmap; either a fixed size, or something based on the length of the audio
using (Bitmap bitmap = new Bitmap((int)Math.Round(reader.TotalTime.TotalSeconds * 40), 200))
{
int width = bitmap.Width;
int height = bitmap.Height;
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
Pen bluePen = new Pen(Color.Blue);
int samplesPerPixel = (int)(reader.Length / (double)(width * bytesPerSample));
int bytesPerPixel = bytesPerSample * samplesPerPixel;
int bytesRead;
byte[] waveData = new byte[bytesPerPixel];
for (float x = 0; x < width; x++)
{
bytesRead = reader.Read(waveData, 0, bytesPerPixel);
if (bytesRead == 0)
break;
short low = 0;
short high = 0;
for (int n = 0; n < bytesRead; n += 2)
{
short sample = BitConverter.ToInt16(waveData, n);
if (sample < low) low = sample;
if (sample > high) high = sample;
}
float lowPercent = ((((float)low) - short.MinValue) / ushort.MaxValue);
float highPercent = ((((float)high) - short.MinValue) / ushort.MaxValue);
float lowValue = height * lowPercent;
float highValue = height * highPercent;
graphics.DrawLine(bluePen, x, lowValue, x, highValue);
}
}
bitmap.Save(audioWaveFormFilePath);
}
}
}
}
catch
{
}
}
That is a wave flow displayer
http://www.codeproject.com/KB/audio-video/wavecontrol.aspx
Check out Zedgraph. It's a free graphing library that works great. There are lots of code samples on their website that allow you to do what you're asking. Zedgraph Downloads Their website seems to be having issues right now, but the download session works and contains all of their sample files.
This will generate waveform from audio file using nAudio...
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string strPath = Server.MapPath("audio/060.mp3");
string SongID = "2";
byte[] bytes = File.ReadAllBytes(strPath);
WriteToFile(SongID,strPath, bytes);
Response.Redirect("Main.aspx");
}
private void WriteToFile(string SongID, string strPath, byte[] Buffer)
{
try
{
int samplesPerPixel = 128;
long startPosition = 0;
//FileStream newFile = new FileStream(GeneralUtils.Get_SongFilePath() + "/" + strPath, FileMode.Create);
float[] data = FloatArrayFromByteArray(Buffer);
Bitmap bmp = new Bitmap(1170, 200);
int BORDER_WIDTH = 5;
int width = bmp.Width - (2 * BORDER_WIDTH);
int height = bmp.Height - (2 * BORDER_WIDTH);
NAudio.Wave.Mp3FileReader reader = new NAudio.Wave.Mp3FileReader(strPath, wf => new NAudio.FileFormats.Mp3.DmoMp3FrameDecompressor(wf));
NAudio.Wave.WaveChannel32 channelStream = new NAudio.Wave.WaveChannel32(reader);
int bytesPerSample = (reader.WaveFormat.BitsPerSample / 8) * channelStream.WaveFormat.Channels;
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.White);
Pen pen1 = new Pen(Color.Gray);
int size = data.Length;
string hexValue1 = "#009adf";
Color colour1 = System.Drawing.ColorTranslator.FromHtml(hexValue1);
pen1.Color = colour1;
Stream wavestream = new NAudio.Wave.Mp3FileReader(strPath, wf => new NAudio.FileFormats.Mp3.DmoMp3FrameDecompressor(wf));
wavestream.Position = 0;
int bytesRead1;
byte[] waveData1 = new byte[samplesPerPixel * bytesPerSample];
wavestream.Position = startPosition + (width * bytesPerSample * samplesPerPixel);
for (float x = 0; x < width; x++)
{
short low = 0;
short high = 0;
bytesRead1 = wavestream.Read(waveData1, 0, samplesPerPixel * bytesPerSample);
if (bytesRead1 == 0)
break;
for (int n = 0; n < bytesRead1; n += 2)
{
short sample = BitConverter.ToInt16(waveData1, n);
if (sample < low) low = sample;
if (sample > high) high = sample;
}
float lowPercent = ((((float)low) - short.MinValue) / ushort.MaxValue);
float highPercent = ((((float)high) - short.MinValue) / ushort.MaxValue);
float lowValue = height * lowPercent;
float highValue = height * highPercent;
g.DrawLine(pen1, x, lowValue, x, highValue);
}
}
string filename = Server.MapPath("image/060.png");
bmp.Save(filename);
bmp.Dispose();
}
catch (Exception e)
{
}
}
public float[] FloatArrayFromStream(System.IO.MemoryStream stream)
{
return FloatArrayFromByteArray(stream.GetBuffer());
}
public float[] FloatArrayFromByteArray(byte[] input)
{
float[] output = new float[input.Length / 4];
for (int i = 0; i < output.Length; i++)
{
output[i] = BitConverter.ToSingle(input, i * 4);
}
return output;
}
}