public void DrawOutput(Graphics g, SwitchBase sw, int index, RenderingEngine e) { const float maxHelpHeight = 400; const float offsetWidth = 5; const float offsetTextX = 24; const float radius = 4; var io = sw.OutputsSet[index]; if (io.IsMouseOver) { var r = io.DescriptionBounds; var swBounds = sw.DescriptionBounds; swBounds.Height = maxHelpHeight; StringFormat format = new StringFormat(); var textBounds = g.MeasureString(this.Title, FontTitle, swBounds.Size, format); var swSizeDesc = new SizeF(240, swBounds.Height); var textDescBounds = g.MeasureString(this.Description, FontDescription, swSizeDesc, format); textDescBounds.Height = Math.Max(textDescBounds.Height, 8); var rText = new RectangleF(r.X + offsetTextX + swBounds.Width, r.Y, textBounds.Width + offsetWidth, textBounds.Height); var rDesc = new RectangleF(r.X + offsetTextX + swBounds.Width, r.Y + textBounds.Height + 2, textDescBounds.Width + offsetWidth, textDescBounds.Height); ExtendedGraphics extendedGraphics = new ExtendedGraphics(g, e); var brush = GetMainBrush(rText); var brushDesc = GetMainBrush(rDesc); extendedGraphics.FillRoundRectangle(brush, rText.X, rText.Y, rText.Width, rText.Height, radius); extendedGraphics.DrawRoundRectangle(Pen, rText.X, rText.Y, rText.Width, rText.Height, radius); extendedGraphics.FillRoundRectangle(brushDesc, rDesc.X, rDesc.Y, rDesc.Width, rDesc.Height, radius); extendedGraphics.DrawRoundRectangle(Pen, rDesc.X, rDesc.Y, rDesc.Width, rDesc.Height, radius); rText = new RectangleF(rText.X + 4, rText.Y, rText.Width, rText.Height); rDesc = new RectangleF(rDesc.X + 4, rDesc.Y, rDesc.Width, rDesc.Height); var r1 = new RectangleF(rText.X - 1 + 0.5f, rText.Y + 0.5f, rText.Width, rText.Height); var r2 = new RectangleF(rText.X - 1, rText.Y, rText.Width, rText.Height); var r3 = new RectangleF(rDesc.X - 1 + 0.5f, rDesc.Y + 0.5f, rDesc.Width, rDesc.Height); var r4 = new RectangleF(rDesc.X - 1, rDesc.Y, rDesc.Width, rDesc.Height); g.DrawString(Title, FontTitle, Brushes.Black, r1, format); g.DrawString(Title, FontTitle, Brushes.White, r2, format); g.DrawString(Description, FontDescription, Brushes.Black, r3, format); g.DrawString(Description, FontDescription, Brushes.White, r4, format); } }
public virtual void DrawGlyph(Graphics g, RenderingEngine e, DrawableBase parent) { var r = DescriptionBounds; if (r.Height > 0) { //r.Height -= compactOffset2 ExtendedGraphics extendedGraphics = new ExtendedGraphics(g, e); float radius = 2; var brush = new SolidBrush(Color.FromArgb(40, 0, 0, 0)); extendedGraphics.FillRoundRectangle(brush, r.X, r.Y + 1, r.Width, r.Height - 1, radius); var img = GlyphImage; if (DrawGlyphImage && img != null) { float ratio = r.Height / img.Height; var imageRect = r; imageRect.Width = img.Width * ratio; imageRect.Height = img.Height * ratio; imageRect.X = r.X + r.Width * 0.5f - imageRect.Width * 0.5f; imageRect.Y = r.Y + r.Height * 0.5f - imageRect.Height * 0.5f; g.DrawImage(img, imageRect); } } }
public virtual void DrawBody(Graphics g, RenderingEngine e, DrawableBase parent) { ExtendedGraphics extendedGraphics = new ExtendedGraphics(g, e); var r = Rectangle; Brush brush; if (IsSelected) { brush = GetMainSelectionBrush(r, e); } else if (DebugMode) { brush = GetDebugBrush(r, e); } else if (DebugDataMode) { brush = GetDebugDataBrush(r, e); } else { brush = GetMainBrush(r, e); } const float radius = 3; extendedGraphics.FillRoundRectangle(brush, r.X, r.Y, r.Width, r.Height, radius); extendedGraphics.DrawRoundRectangle(Pen, r.X, r.Y, r.Width, r.Height, radius); }
public void Draw(Graphics g, SwitchBase sw, DrawableBase parent, RenderingEngine e) { const float offset = 10; const float radius = 4; var r = sw.SelectionBounds; StringFormat format = new StringFormat(); var textBounds = g.MeasureString(this.Title, FontTitle, r.Size, format); r = new RectangleF(r.X, r.Y - offset - textBounds.Height, r.Width, textBounds.Height); ExtendedGraphics extendedGraphics = new ExtendedGraphics(g, e); var brush = GetMainBrush(r); extendedGraphics.FillRoundRectangle(brush, r.X, r.Y, r.Width, r.Height, radius); extendedGraphics.DrawRoundRectangle(Pen, r.X, r.Y, r.Width, r.Height, radius); r = new RectangleF(r.X + 4, r.Y, r.Width, r.Height); var r1 = new RectangleF(r.X + 0.5f, r.Y + 0.5f, r.Width, r.Height); var r2 = new RectangleF(r.X, r.Y, r.Width, r.Height); g.DrawString(Title, FontTitle, Brushes.Black, r1, format); g.DrawString(Title, FontTitle, Brushes.White, r2, format); }
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; if (navBitmap == null) { g.FillRectangle(new SolidBrush(Color.White), e.ClipRectangle); } else { g.DrawImage(navBitmap, 0, 0); } // Find the current viewport int x = StaticUtils.GetScrollPos(timeline.Handle, StaticUtils.SB_HORZ); int y = StaticUtils.GetScrollPos(timeline.Handle, StaticUtils.SB_VERT); if (x >= 0 && y >= 0) { float ratioX, ratioY; GetRatios(out ratioX, out ratioY); int w = timeline.ClientRectangle.Width; int h = timeline.ClientRectangle.Height; Pen pen = new Pen(ForeColor); // Scale it down to our miniature x = (int)((float)x * ratioX); y = (int)((float)y * ratioY); w = (int)((float)w * ratioX); if (w >= ClientRectangle.Width) { w = ClientRectangle.Width - (int)pen.Width; } h = (int)((float)h * ratioY); if (h >= ClientRectangle.Height) { h = ClientRectangle.Height - (int)pen.Width; } if (w < 1) { w = 1; } if (h < 1) { h = 1; } ExtendedGraphics eg = new ExtendedGraphics(g); eg.FillRoundRectangle(new SolidBrush(Color.FromArgb(127, 0x9B, 0x57, 0x9F)), x, y, w, h, 3); eg.DrawRoundRectangle(pen, x, y, w, h, 3); } }
/// <summary> /// Draws the background. /// </summary> /// <param name="graphics">The graphics object we render to.</param> /// <param name="nvd">The view data of this node in the current view.</param> /// <param name="renderDepth">The depth which is still rendered.</param> /// <param name="padding">The padding between the nodes.</param> public void DrawBackground(Graphics graphics, NodeViewData nvd, int renderDepth, SizeF padding) { SizeF size = nvd.GetTotalSize(padding.Width, renderDepth); if (_backgroundColor != CommentColor.NoColor) { float commentPadding = Math.Min(padding.Height, padding.Width) * 0.75f; ExtendedGraphics extended = new ExtendedGraphics(graphics); extended.FillRoundRectangle(_backgroundBrush, nvd.LayoutRectangle.X - commentPadding * 0.5f, nvd.LayoutRectangle.Y - commentPadding * 0.5f, size.Width + commentPadding, size.Height + commentPadding, 6.0f); } }
private Bitmap GetHeadingBitmap() { int w = headingColsRect.X + (sessions.Count * (colWidth + colSpacing)); int h = headingColsRect.Y + headingColsRect.Height + 3; // FIXME Bitmap bitmap = new Bitmap(w, h); Graphics g = Graphics.FromImage(bitmap); ExtendedGraphics eg = new ExtendedGraphics(g); Brush fgBrush = new SolidBrush(Color.White); Font headerFont = new Font("Tahoma", 10, FontStyle.Bold); int x = headingColsRect.X; Pen selectedPen = new Pen(Color.Black, 3); foreach (VisualSession stream in sessions) { string localEpStr = stream.LocalEndpoint.ToString(); string remoteEpStr = stream.RemoteEndpoint.ToString(); string str; if (localEpStr.Length > 0 && remoteEpStr.Length > 0) { str = String.Format("{0} <-> {1}", localEpStr, remoteEpStr); } else { str = "<UNKNOWN ENDPOINTS>"; } Brush bgBrush = new SolidBrush(colorPool.GetColorForId(Convert.ToString(str.GetHashCode()))); eg.FillRoundRectangle(bgBrush, x, headingColsRect.Y, colWidth, headingColsRect.Height, 2.0f); if (selectedSessions.ContainsKey(stream)) { eg.DrawRoundRectangle(selectedPen, x, headingColsRect.Y, colWidth, headingColsRect.Height, 2.0f); } SizeF fs = g.MeasureString(str, headerFont); g.DrawString(str, headerFont, fgBrush, x + (colWidth / 2) - (fs.Width / 2), headingColsRect.Y + ((headingColsRect.Height / 2) - (fs.Height / 2))); x += colWidth + colSpacing; } return(bitmap); }
public virtual void DrawDescription(Graphics g, RenderingEngine e, DrawableBase parent) { ExtendedGraphics extendedGraphics = new ExtendedGraphics(g, e); var rect = Rectangle; const float offset = 2f; const float offset2 = 4f; float compactOffset = DescriptionOffsetLeftCompact; float compactOffset2 = DescriptionOffsetLeftCompact + DescriptionOffsetRightCompact; var r = new RectangleF(rect.X + compactOffset, rect.Y + offset, rect.Width - compactOffset2, DescriptionHeight - offset2); float radius = 2; var brush = new SolidBrush(Color.FromArgb(80, 0, 0, 0)); extendedGraphics.FillRoundRectangle(brush, r.X, r.Y, r.Width, r.Height, radius); extendedGraphics.DrawRoundRectangle(DescriptionPen, r.X, r.Y, r.Width, r.Height, radius); }
private void AquaButton_Paint(object sender, PaintEventArgs e) { Graphics g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; ExtendedGraphics eg = new ExtendedGraphics(g); //SolidBrush br1 = new SolidBrush(Color.FromArgb(130, 125,236,255)); LinearGradientBrush br1 = new LinearGradientBrush( new Point(60, 0), new Point(60, 28), Color.FromArgb(125, 236, 255), Color.FromArgb(0, 130, 255) ); eg.FillRoundRectangle(br1, 1, 1, 124, 25, 12); if (m_IsMouseOver) { GraphicsPath GP = new GraphicsPath(); GP.AddEllipse(25, -7, 70, 70); PathGradientBrush PGB = new PathGradientBrush(GP); PGB.CenterColor = Color.FromArgb(0, 255, 0); PGB.SurroundColors = new Color[] { Color.FromArgb(0, 0, 0, 0) }; g.FillRectangle(PGB, 0, 0, 130, 26); } Pen pn1 = new Pen(Color.Black, 2f); eg.DrawRoundRectangle(pn1, 1, 1, 124, 25, 12); Rectangle rect1 = new Rectangle(0, 0, this.Width, this.Height); StringFormat strForm = new StringFormat(); strForm.Alignment = StringAlignment.Center; strForm.LineAlignment = StringAlignment.Center; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; g.DrawString(m_text, new Font(FontFamily.GenericSansSerif, 11, FontStyle.Bold), Brushes.Black, rect1, strForm ); }
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; if (navBitmap == null) { g.FillRectangle(new SolidBrush(Color.White), e.ClipRectangle); } else { g.DrawImage(navBitmap, 0, 0); } // Find the current viewport int x = StaticUtils.GetScrollPos(timeline.Handle, StaticUtils.SB_HORZ); int y = StaticUtils.GetScrollPos(timeline.Handle, StaticUtils.SB_VERT); if (x >= 0 && y >= 0) { float ratioX, ratioY; GetRatios(out ratioX, out ratioY); int w = timeline.ClientRectangle.Width; int h = timeline.ClientRectangle.Height; Pen pen = new Pen(ForeColor); // Scale it down to our miniature x = (int) ((float)x * ratioX); y = (int) ((float)y * ratioY); w = (int) ((float)w * ratioX); if (w >= ClientRectangle.Width) w = ClientRectangle.Width - (int) pen.Width; h = (int) ((float)h * ratioY); if (h >= ClientRectangle.Height) h = ClientRectangle.Height - (int) pen.Width; ExtendedGraphics eg = new ExtendedGraphics(g); eg.FillRoundRectangle(new SolidBrush(Color.FromArgb(127, 0x9B, 0x57, 0x9F)), x, y, w, h, 3); eg.DrawRoundRectangle(pen, x, y, w, h, 3); } }
/// <summary> /// Draws the background. /// </summary> /// <param name="graphics">The graphics object we render to.</param> /// <param name="nvd">The view data of this node in the current view.</param> /// <param name="renderDepth">The depth which is still rendered.</param> /// <param name="padding">The padding between the nodes.</param> public void DrawBackground(Graphics graphics, NodeViewData nvd, int renderDepth, SizeF padding) { SizeF size = nvd.GetTotalSize(padding.Width, renderDepth); if (_backgroundColor != CommentColor.NoColor) { float commentPadding = Math.Min(padding.Height, padding.Width) * 0.75f; ExtendedGraphics extended = new ExtendedGraphics(graphics); extended.FillRoundRectangle(_backgroundBrush, nvd.LayoutRectangle.X - commentPadding * 0.5f, nvd.LayoutRectangle.Y - commentPadding * 0.5f, size.Width + commentPadding, size.Height + commentPadding, 0.05f); } }
public override void Draw(Graphics g, RenderingEngine e, DrawableBase parent) { ExtendedGraphics extendedGraphics = new ExtendedGraphics(g, e); var r = DescriptionBounds; float radius = 2; Brush brush; if (IsMouseOver) { brush = new SolidBrush(Color.FromArgb(150, 155, 22, 0)); } else if (HasFocus) { brush = new SolidBrush(Color.FromArgb(150, 50, 125, 15)); } else if (ReadOnly) { brush = new SolidBrush(Color.FromArgb(110, 250, 200, 0)); } else { brush = new SolidBrush(Color.FromArgb(80, 0, 0, 0)); } if (!ReadOnly) { extendedGraphics.FillRoundRectangle(brush, r.X, r.Y, r.Width, r.Height, radius); } extendedGraphics.DrawRoundRectangle(DescriptionPen, r.X, r.Y, r.Width, r.Height, radius); PointF fontPoint = new PointF(r.X + 1, r.Y - 2); var renderingHint = g.TextRenderingHint; g.TextRenderingHint = TextRenderingHint.AntiAlias; RectangleF fontRect1 = new RectangleF(fontPoint.X - 1, fontPoint.Y, r.Width, r.Height); RectangleF fontRect2 = new RectangleF(fontPoint.X - 0.5f, fontPoint.Y + 0.5f, r.Width, r.Height); g.DrawString(Text, FontSmall, Brushes.Black, fontRect1, StringFormat); g.DrawString(Text, FontSmall, Brushes.White, fontRect2, StringFormat); if (AutoResize) { SizeF sizeFull = new SizeF(); if (Text.Length > 0) { sizeFull = g.MeasureString(Text, FontSmall, fontPoint, StringFormat); } float widthDiff = parent.Size.Width - r.Width; float minWidth = Math.Max(ParentWidth, sizeFull.Width + widthDiff); parent.ColumnWidth = minWidth; } g.TextRenderingHint = renderingHint; base.Draw(g, e, parent); }
private Bitmap GetHeadingBitmap() { int w = headingColsRect.X + (sessions.Count * (colWidth + colSpacing)); int h = headingColsRect.Y + headingColsRect.Height + 3; // FIXME Bitmap bitmap = new Bitmap(w, h); Graphics g = Graphics.FromImage(bitmap); ExtendedGraphics eg = new ExtendedGraphics(g); Brush fgBrush = new SolidBrush(Color.White); Font headerFont = new Font("Tahoma", 10, FontStyle.Bold); int x = headingColsRect.X; Pen selectedPen = new Pen(Color.Black, 3); foreach (VisualSession stream in sessions) { string str = stream.Name; Brush bgBrush = new SolidBrush(colorPool.GetColorForId(Convert.ToString(str.GetHashCode()))); eg.FillRoundRectangle(bgBrush, x, headingColsRect.Y, colWidth, headingColsRect.Height, 2.0f); if (selectedSessions.ContainsKey(stream)) { eg.DrawRoundRectangle(selectedPen, x, headingColsRect.Y, colWidth, headingColsRect.Height, 2.0f); } SizeF fs = g.MeasureString(str, headerFont); g.DrawString(str, headerFont, fgBrush, x + (colWidth / 2) - (fs.Width / 2), headingColsRect.Y + ((headingColsRect.Height / 2) - (fs.Height / 2))); x += colWidth + colSpacing; } return bitmap; }
/// <summary> /// Draw a waveform using start and end zoom sample position /// </summary> /// <param name="audioData">The audio data (mono)</param> /// <param name="imageSize">Size of the image</param> /// <param name="amplitude">Amplitude (1 is default)</param> /// <param name="startZoomSamplePosition">First Sample to Zoom in on</param> /// <param name="endZoomSamplePosition">Last Sample to Zoom in on</param> /// <param name="sampleRate">Samplerate of the audio data (to calculate time)</param> /// <param name="drawRaw">Whether to draw only the raw image (no margins)</param> /// <seealso cref="https://github.com/aalin/canvas_waveform"></seealso> /// <seealso cref="http://www.hisschemoller.com/2010/mp3-wave-display/"></seealso> /// <seealso cref="http://www.marinbezhanov.com/web-development/14/actionscript-3-sound-extract-demystified-or-how-to-draw-a-waveform-in-flash/"></seealso> /// <seealso cref="http://stackoverflow.com/questions/1215326/open-source-c-sharp-code-to-present-wave-form"></seealso> /// <returns>A bitmap of the waveform</returns> public static Bitmap DrawWaveform(float[] audioData, Size imageSize, int amplitude, int startZoomSamplePosition, int endZoomSamplePosition, double sampleRate, bool drawRaw=false) { // Basic constants int TOTAL_HEIGHT = imageSize.Height; // Height of graph int TOTAL_WIDTH = imageSize.Width; // Width of graph int TOP = 5; // Top of graph int LEFT = 5; // Left edge of graph if (drawRaw) { TOP = 0; // Top of graph LEFT = 0; // Left edge of graph } int HEIGHT = imageSize.Height-2*TOP; // Height of graph int WIDTH = imageSize.Width-2*LEFT; // Width of graph // limit amplitude if (amplitude > 5000) { amplitude = 5000; } float MIN_AMPLITUDE = -1.0f / amplitude; float MAX_AMPLITUDE = 1.0f / amplitude; float AMPLITUDE_STEP = MAX_AMPLITUDE / 5; string LABEL_X = "Time"; // Label for X axis string LABEL_Y = "Amplitude"; // Label for Y axis bool drawLabels = false; bool drawRoundedRectangles = true; bool displayInformationBox = true; bool displayTime = true; bool useAverages = false; // averages draws a "filled" waveform if (drawRaw) { drawLabels = false; drawRoundedRectangles = false; displayInformationBox = false; displayTime = false; } // Colors Color lineColor = ColorTranslator.FromHtml("#C7834C"); Color middleLineColor = ColorTranslator.FromHtml("#EFAB74"); Color textColor = ColorTranslator.FromHtml("#A9652E"); Color sampleColor = ColorTranslator.FromHtml("#4C2F1A"); Color fillOuterColor = ColorTranslator.FromHtml("#FFFFFF"); Color fillColor = ColorTranslator.FromHtml("#F9C998"); Color textInfoBoxColor = ColorTranslator.FromHtml("#4C2F1A"); Color textInfoBoxBgColor = ColorTranslator.FromHtml("#F7DECA"); // Derived constants int CENTER = TOTAL_HEIGHT / 2; int RIGHT = WIDTH; int BOTTOM = TOTAL_HEIGHT-TOP; // Bottom of graph int totalNumberOfSamples = 0; float[] data = null; float samplesPerPixel = 0; if (audioData != null && audioData.Length > 0) { totalNumberOfSamples = audioData.Length; // make sure the zoom start and zoom end is correct if (startZoomSamplePosition < 0) startZoomSamplePosition = 0; if (endZoomSamplePosition > audioData.Length || endZoomSamplePosition < 0) endZoomSamplePosition = audioData.Length; if (endZoomSamplePosition != 0) { data = new float[endZoomSamplePosition-startZoomSamplePosition]; Array.Copy(audioData, startZoomSamplePosition, data, 0, endZoomSamplePosition-startZoomSamplePosition); samplesPerPixel = (float) (endZoomSamplePosition - startZoomSamplePosition) / (float) WIDTH; } else { data = audioData; samplesPerPixel = (float) totalNumberOfSamples / (float) WIDTH; } } double totalDurationMs = totalNumberOfSamples / sampleRate * 1000; float MAX_TIME = (float) (endZoomSamplePosition / sampleRate * 1000); float MIN_TIME = 0.0f; if (startZoomSamplePosition > 0) { MIN_TIME = (float) (startZoomSamplePosition / sampleRate * 1000); } float TIME_STEP = (float) MathUtils.GetNicerNumber((MAX_TIME-MIN_TIME) / 10); float AMPLITUDETOPIXEL = (float) HEIGHT/(MAX_AMPLITUDE-MIN_AMPLITUDE); // Pixels/tick float TIMETOPIXEL = (float) WIDTH/(MAX_TIME-MIN_TIME); // Pixels/second // Set up for drawing Bitmap png = new Bitmap( TOTAL_WIDTH, TOTAL_HEIGHT, PixelFormat.Format32bppArgb ); Graphics g = Graphics.FromImage(png); ExtendedGraphics eg = new ExtendedGraphics(g); Pen linePen = new Pen(lineColor, 0.5f); Pen middleLinePen = new Pen(middleLineColor, 0.5f); Pen textPen = new Pen(textColor, 1.0f); Pen samplePen = new Pen(sampleColor, 1.0f); Pen infoBoxPen = new Pen(textInfoBoxColor, 1.0f); // Draw a rectangular box marking the boundaries of the graph // Create outer rectangle. Rectangle rectOuter = new Rectangle(0, 0, TOTAL_WIDTH, TOTAL_HEIGHT); Brush fillBrushOuter = new SolidBrush(fillOuterColor); g.FillRectangle(fillBrushOuter, rectOuter); // Create rectangle. Rectangle rect = new Rectangle(LEFT, TOP, WIDTH, HEIGHT); Brush fillBrush = new SolidBrush(fillColor); if (drawRoundedRectangles) { eg.FillRoundRectangle(fillBrush, rect.X, rect.Y, rect.Width, rect.Height, 10); eg.DrawRoundRectangle(linePen, rect.X, rect.Y, rect.Width, rect.Height, 10); } else { g.FillRectangle(fillBrush, rect); g.DrawRectangle(linePen, rect); } // Label for horizontal axis Font drawLabelFont = new Font("Arial", 8); SolidBrush drawLabelBrush = new SolidBrush(textPen.Color); if (drawLabels) { SizeF drawLabelTextSize = g.MeasureString(LABEL_X, drawLabelFont); g.DrawString(LABEL_X, drawLabelFont, drawLabelBrush, (TOTAL_WIDTH/2) - (drawLabelTextSize.Width/2), TOTAL_HEIGHT - drawLabelFont.GetHeight(g) -3); } float y = 0; float yMiddle = 0; float x = 0; float xMiddle = 0; for ( float amplitudeTick = MIN_AMPLITUDE; amplitudeTick <= MAX_AMPLITUDE; amplitudeTick += AMPLITUDE_STEP ) { // draw horozontal main line y = BOTTOM - AMPLITUDETOPIXEL*(amplitudeTick-MIN_AMPLITUDE); if (y < BOTTOM && y > TOP+1) { g.DrawLine(linePen, LEFT, y, LEFT+WIDTH, y); } // draw horozontal middle line (between the main lines) yMiddle = y-(AMPLITUDETOPIXEL*AMPLITUDE_STEP)/2; if (yMiddle > 0) { g.DrawLine(middleLinePen, LEFT, yMiddle, LEFT+WIDTH, yMiddle); } if ( amplitudeTick != MAX_AMPLITUDE ) { // Numbers on the tick marks Font drawFont = new Font("Arial", 8); SolidBrush drawBrush = new SolidBrush(textPen.Color); //g.DrawString("" + amplitudeTick, drawFont, drawBrush, LEFT+5, y - drawFont.GetHeight(g) -2); g.DrawString(amplitudeTick.ToString("0.000000"), drawFont, drawBrush, LEFT+5, y - drawFont.GetHeight(g) -2); } } if (drawLabels) { // Label for vertical axis g.DrawString(LABEL_Y, drawLabelFont, drawLabelBrush, 1, TOP + HEIGHT/2 - drawLabelFont.GetHeight(g)/2); } // Tick marks on the horizontal axis for ( float timeTick = MIN_TIME; timeTick <= MAX_TIME; timeTick += TIME_STEP ) { // draw vertical main line x = LEFT + TIMETOPIXEL*(timeTick-MIN_TIME); if (x > LEFT && x < WIDTH) { g.DrawLine(linePen, x, BOTTOM, x, TOP); } // draw vertical middle line (between the main lines) xMiddle = x + TIMETOPIXEL*TIME_STEP/2; if (xMiddle < TOTAL_WIDTH) { g.DrawLine(middleLinePen, xMiddle, BOTTOM, xMiddle, TOP); } if ( timeTick != MIN_TIME && timeTick != MAX_TIME ) { // Numbers on the tick marks Font drawFont = new Font("Arial", 8); SolidBrush drawBrush = new SolidBrush(textPen.Color); TimeSpan time = TimeSpan.FromMilliseconds(timeTick); //g.DrawString("" + timeTick + " ms", drawFont, drawBrush, x, TOP +2); g.DrawString(time.ToString(@"hh\:mm\:ss\.FFFFFFF"), drawFont, drawBrush, x, TOP +2); } } if (displayTime) { string displayTimeString = String.Format("Duration: {0} samples @ {1:0.0000} ms", totalNumberOfSamples, totalDurationMs); SizeF displayTimeStringTextSize = g.MeasureString(displayTimeString, drawLabelFont); g.DrawString(displayTimeString, drawLabelFont, drawLabelBrush, TOTAL_WIDTH - displayTimeStringTextSize.Width - 10, TOTAL_HEIGHT - drawLabelFont.GetHeight(g) - 10); } // draw middle line g.DrawLine(middleLinePen, LEFT, CENTER, WIDTH, CENTER); // Draw waveform if (data != null && data.Length > 0) { if (samplesPerPixel >= 1) { // the number of samples are greater than the available drawing space (i.e. greater than the number of pixles in the X-Axis) float xPrev = 0; float yPrev = 0; float yAxis = 0; int yMax = 0; int yMin = 0; int yMaxPrev = 0; int yMinPrev = 0; bool firstPoint = true; for (int xAxis = 0; xAxis < WIDTH; xAxis++) { // determine start and end points within WAV (for this single pixel on the X axis) int start = (int)((float)(xAxis) * samplesPerPixel); int end = (int)((float)(xAxis + 1) * samplesPerPixel); // reset the min and max values yMax = 0; yMin = 0; if (useAverages) { // determine the average min and max values within this specific range float posAvg = 0, negAvg = 0; MathUtils.Averages(data, start, end, out posAvg, out negAvg); yMax = TOP + HEIGHT - (int)((posAvg * amplitude + 1) * 0.5 * HEIGHT); yMin = TOP + HEIGHT - (int)((negAvg * amplitude + 1) * 0.5 * HEIGHT); g.DrawLine(samplePen, xAxis + LEFT, yMin, xAxis + LEFT, yMax); } else { // determine the min and max values within this specific range float min = float.MaxValue; float max = float.MinValue; for (int i = start; i <= end; i++) { if (i < data.Length) { float val = data[i]; min = val < min ? val : min; max = val > max ? val : max; } } yMax = TOP + HEIGHT - (int)((max * amplitude + 1) * 0.5 * HEIGHT); yMin = TOP + HEIGHT - (int)((min * amplitude + 1) * 0.5 * HEIGHT); // limit within the drawing space if (yMax < 0) yMax = 0; if (yMin > HEIGHT) yMin = HEIGHT; // make sure that we always draw something if (yMin == yMax) { yMin += 1; } yAxis = yMax; // draw waveform // If it's the first point if ( firstPoint ) { // Move to the point xPrev = xAxis; yPrev = yAxis; yMaxPrev = yMax; yMinPrev = yMin; firstPoint = false; } else { if (TIMETOPIXEL > 10) { // For smaller resolution, Draw line from the previous point g.DrawLine(samplePen, xPrev + LEFT, yPrev, xAxis + LEFT, yAxis); // Try to smooth the lines by using the previous max value //g.DrawLine(samplePen, xPrev + LEFT, yMaxPrev, xAxis + LEFT, yMin); } else { // use yMax and yMin // original from example: http://stackoverflow.com/questions/1215326/open-source-c-sharp-code-to-present-wave-form // basically don't care about previous x or y, but draw vertical lines // from y min to y max value g.DrawLine(samplePen, xAxis + LEFT, yMin, xAxis + LEFT, yMax); } // store values to next iteration xPrev = xAxis; yPrev = yAxis; yMaxPrev = yMax; yMinPrev = yMin; } } } } else { // the number of samples are less than the available drawing space // (i.e. less than the number of pixles in the X-Axis) int samples = data.Length; if (samples > 1) { // at least two samples float mult_x = (float) WIDTH / (endZoomSamplePosition-startZoomSamplePosition - 1); List<Point> ps = new List<Point>(); for (int i = 0; i < data.Length; i++) { x = (i * mult_x) + LEFT; y = TOP + HEIGHT - (int)((data[i] * amplitude + 1) * 0.5 * HEIGHT); Point p = new Point((int)x, (int)y); ps.Add(p); } if (ps.Count > 0) { g.DrawLines(samplePen, ps.ToArray()); } } else { // we have only one sample, draw a flat line g.DrawLine(linePen, 0, 0.5f * HEIGHT, WIDTH, 0.5f * HEIGHT); } } } // draw right upper box if (displayInformationBox) { Font drawInfoBoxFont = new Font("Arial", 8); SolidBrush drawInfoBoxBrush = new SolidBrush(infoBoxPen.Color); string infoBoxLine1Text = String.Format("SampleToPixel Orig: {0:0.000} => New: {1:0.000}", (float) totalNumberOfSamples / WIDTH, samplesPerPixel); string infoBoxLine2Text = String.Format("Time (Min->Max): {0} -> {1}", MIN_TIME, MAX_TIME); string infoBoxLine3Text = String.Format("Timestep: {0}, TimeToPixel: {1}", TIME_STEP, TIMETOPIXEL); // get box width int infoBoxMargin = 5; List<float> textLineSizes = new List<float>(); textLineSizes.Add(g.MeasureString(infoBoxLine1Text, drawInfoBoxFont).Width + infoBoxMargin*2); textLineSizes.Add(g.MeasureString(infoBoxLine2Text, drawInfoBoxFont).Width + infoBoxMargin*2); textLineSizes.Add(g.MeasureString(infoBoxLine3Text, drawInfoBoxFont).Width + infoBoxMargin*2); textLineSizes.Add(150.0f); // info box minimum width float infoBoxLineTextWidth = 0.0f; float minWidth = 0.0f; MathUtils.ComputeMinAndMax(textLineSizes.ToArray(), out minWidth, out infoBoxLineTextWidth); int infoBoxWidth = (int) infoBoxLineTextWidth; float infoBoxLineTextHeight = drawInfoBoxFont.GetHeight(g); int infoBoxHeight = (int) (infoBoxMargin + (infoBoxLineTextHeight + infoBoxMargin)*4); Rectangle rectInfoBox = new Rectangle(WIDTH - infoBoxWidth - 20, 30, infoBoxWidth, infoBoxHeight); Brush fillBrushInfoBox = new SolidBrush(textInfoBoxBgColor); g.FillRectangle(fillBrushInfoBox, rectInfoBox); g.DrawRectangle(linePen, rectInfoBox); g.DrawString(infoBoxLine1Text, drawInfoBoxFont, drawInfoBoxBrush, WIDTH - infoBoxWidth - 20 + infoBoxMargin, 30 + infoBoxMargin); g.DrawString(infoBoxLine2Text, drawInfoBoxFont, drawInfoBoxBrush, WIDTH - infoBoxWidth - 20 + infoBoxMargin, 30 + infoBoxMargin + (infoBoxLineTextHeight + infoBoxMargin)); g.DrawString(infoBoxLine3Text, drawInfoBoxFont, drawInfoBoxBrush, WIDTH - infoBoxWidth - 20 + infoBoxMargin, 30 + infoBoxMargin + (infoBoxLineTextHeight + infoBoxMargin)*2); } return png; }
/// <summary> /// Get a spectrum of the signal specified at the input /// </summary> /// <param name="mag">array of magnitude values as decibel</param> /// <param name="freq">array of frequency values as herz</param> /// <param name="imageSize">Size of image</param> /// <param name="minFrequency">minimum frequency to show</param> /// <param name="maxFrequency">maximum frequency to show</param> /// <param name="foundMaxDecibel">if specified output max decibel text</param> /// <param name="foundMaxFrequency">if specified output max frequency text</param> /// <returns>Spectral image of the signal</returns> /// <remarks>This code is based on the code by Gerald T. Beauregard /// which was released under the MIT License. (Copyright (c) 2010 Gerald T. Beauregard) /// The code were ported to C# and heavily modifified by Per Ivar Nerseth, 2012 /// </remarks> public static Bitmap GetSpectrumImage(ref float[] mag, ref float[] freq, Size imageSize, float minFrequency = 0, float maxFrequency = 20000, float foundMaxDecibel = -1, float foundMaxFrequency = -1) { // Basic constants int TOTAL_HEIGHT = imageSize.Height; // Height of graph int TOTAL_WIDTH = imageSize.Width; // Width of graph float MIN_FREQ = minFrequency; // Minimum frequency (Hz) on horizontal axis. float MAX_FREQ = maxFrequency; // Maximum frequency (Hz) on horizontal axis. float FREQ_STEP = 2000; // Interval between ticks (Hz) on horizontal axis. float MAX_DB = -0.0f; // Maximum dB magnitude on vertical axis. float MIN_DB = -100.0f; //-60 // Minimum dB magnitude on vertical axis. float DB_STEP = 20; // Interval between ticks (dB) on vertical axis. int TOP = 5; // Top of graph int LEFT = 5; // Left edge of graph int HEIGHT = imageSize.Height-2*TOP; // Height of graph int WIDTH = imageSize.Width-2*LEFT; // Width of graph string LABEL_X = "Frequency (Hz)"; // Label for X axis string LABEL_Y = "dB"; // Label for Y axis bool drawLabels = false; bool drawRoundedRectangles = true; // if the max frequency gets lower than ... lower the frequency step if (MAX_FREQ < 20000) { FREQ_STEP = (float) MathUtils.GetNicerNumber(MAX_FREQ / 10); } // Colors Color lineColor = ColorTranslator.FromHtml("#C7834C"); Color middleLineColor = ColorTranslator.FromHtml("#EFAB74"); Color textColor = ColorTranslator.FromHtml("#A9652E"); Color sampleColor = ColorTranslator.FromHtml("#4C2F1A"); Color fillOuterColor = ColorTranslator.FromHtml("#FFFFFF"); Color fillColor = ColorTranslator.FromHtml("#F9C998"); // Derived constants int BOTTOM = TOTAL_HEIGHT-TOP; // Bottom of graph float DBTOPIXEL = (float) HEIGHT/(MAX_DB-MIN_DB); // Pixels/tick float FREQTOPIXEL = (float) WIDTH/(MAX_FREQ-MIN_FREQ); // Pixels/Hz try { Bitmap png = new Bitmap( TOTAL_WIDTH, TOTAL_HEIGHT, PixelFormat.Format32bppArgb ); Graphics g = Graphics.FromImage(png); ExtendedGraphics eg = new ExtendedGraphics(g); int numPoints = mag.Length; if ( mag.Length != freq.Length ) System.Diagnostics.Debug.WriteLine( "mag.length != freq.length" ); Pen linePen = new Pen(lineColor, 0.5f); Pen middleLinePen = new Pen(middleLineColor, 0.5f); Pen textPen = new Pen(textColor, 1); Pen samplePen = new Pen(sampleColor, 1); // Draw a rectangular box marking the boundaries of the graph // Create outer rectangle. Rectangle rectOuter = new Rectangle(0, 0, TOTAL_WIDTH, TOTAL_HEIGHT); Brush fillBrushOuter = new SolidBrush(fillOuterColor); g.FillRectangle(fillBrushOuter, rectOuter); // Create rectangle. Rectangle rect = new Rectangle(LEFT, TOP, WIDTH, HEIGHT); Brush fillBrush = new SolidBrush(fillColor); if (drawRoundedRectangles) { eg.FillRoundRectangle(fillBrush, rect.X, rect.Y, rect.Width, rect.Height, 10); eg.DrawRoundRectangle(linePen, rect.X, rect.Y, rect.Width, rect.Height, 10); } else { g.FillRectangle(fillBrush, rect); g.DrawRectangle(linePen, rect); } // Label for horizontal axis Font drawLabelFont = new Font("Arial", 8); SolidBrush drawLabelBrush = new SolidBrush(textPen.Color); if (drawLabels) { SizeF drawLabelTextSize = g.MeasureString(LABEL_X, drawLabelFont); g.DrawString(LABEL_X, drawLabelFont, drawLabelBrush, (TOTAL_WIDTH/2) - (drawLabelTextSize.Width/2), TOTAL_HEIGHT - drawLabelFont.GetHeight(g) -3); } float y = 0; float yMiddle = 0; float x = 0; float xMiddle = 0; for ( float dBTick = MIN_DB; dBTick <= MAX_DB; dBTick += DB_STEP ) { // draw horozontal main line y = BOTTOM - DBTOPIXEL*(dBTick-MIN_DB); if (y < BOTTOM && y > TOP+1) { g.DrawLine(linePen, LEFT, y, LEFT+WIDTH, y); } // draw horozontal middle line (between the main lines) yMiddle = y-(DBTOPIXEL*DB_STEP)/2; if (yMiddle > 0) { g.DrawLine(middleLinePen, LEFT, yMiddle, LEFT+WIDTH, yMiddle); } if ( dBTick != MAX_DB ) { // Numbers on the tick marks Font drawFont = new Font("Arial", 8); SolidBrush drawBrush = new SolidBrush(textPen.Color); g.DrawString("" + dBTick + " dB", drawFont, drawBrush, LEFT+5, y - drawFont.GetHeight(g) -2); } } if (drawLabels) { // Label for vertical axis g.DrawString(LABEL_Y, drawLabelFont, drawLabelBrush, 1, TOP + HEIGHT/2 - drawLabelFont.GetHeight(g)/2); } // Tick marks on the horizontal axis for ( float f = MIN_FREQ; f <= MAX_FREQ; f += FREQ_STEP ) { // draw vertical main line x = LEFT + FREQTOPIXEL*(f-MIN_FREQ); if (x > LEFT && x < WIDTH) { g.DrawLine(linePen, x, BOTTOM, x, TOP); } // draw vertical middle line (between the main lines) xMiddle = x + FREQTOPIXEL*FREQ_STEP/2; if (xMiddle < TOTAL_WIDTH) { g.DrawLine(middleLinePen, xMiddle, BOTTOM, xMiddle, TOP); } if ( f != MIN_FREQ && f != MAX_FREQ ) { // Numbers on the tick marks Font drawFont = new Font("Arial", 8); SolidBrush drawBrush = new SolidBrush(textPen.Color); g.DrawString("" + f + " Hz", drawFont, drawBrush, x, TOP +2); } } if (foundMaxDecibel != -1 && foundMaxFrequency != -1) { int note = 0; int cents = 0; MidiUtils.PitchToMidiNote(foundMaxFrequency, out note, out cents); string noteName = MidiUtils.GetNoteName(note, false, true); //string foundMax = String.Format("Max found: {0}dB @ {1} hz", foundMaxDecibel, foundMaxFrequency); string foundMax = String.Format("Max found: {0}dB @ {1} hz ({2} - Note: {3} {4:+#;-#;0} cents)", foundMaxDecibel, foundMaxFrequency, noteName, note, cents); SizeF foundMaxLabelTextSize = g.MeasureString(foundMax, drawLabelFont); g.DrawString(foundMax, drawLabelFont, drawLabelBrush, TOTAL_WIDTH - foundMaxLabelTextSize.Width - 10, TOTAL_HEIGHT - drawLabelFont.GetHeight(g) - 10); } // The line in the graph int i = 0; // Ignore points that are too far to the left for ( i = 0; i < numPoints && freq[i] < MIN_FREQ; i++ ) { } // For all remaining points within range of x-axis float oldX = 0; float oldY = TOP; bool firstPoint = true; for ( ; i < numPoints && freq[i] <= MAX_FREQ; i++ ) { // Compute horizontal position x = LEFT + FREQTOPIXEL*(freq[i]-MIN_FREQ); // Compute vertical position of point // and clip at top/bottom. y = BOTTOM - DBTOPIXEL*(mag[i]-MIN_DB); if ( y < TOP ) y = TOP; else if ( y > BOTTOM ) y = BOTTOM; // If it's the first point if ( firstPoint ) { // Move to the point oldX = x; oldY = y; firstPoint = false; } else { // Otherwise, draw line from the previous point g.DrawLine(samplePen, oldX, oldY, x, y); oldX = x; oldY = y; } } return png; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); return null; } }