title: DataImage with comma/base64 encoded - comma disappears
body: <p>I've a piece of code that is taking an equation and converting it to a .png image for display.
  If the equation contains a comma(,) - upon conversion to the .png, the , is lost if the image byte string has been base64 encoded.
  If not, everything is fine and the comma displays.
  An example -
  Non base64 - equation 1,2 displays as image of 1,2
  Base64 - equation 1,2 display as image of 12</p>
  
  <p>The equation is derived from the querystring. eg - </p>
  
  <pre><code>/.../.../GetEquationImage.aspx?eq=1%2C3&amp;fontsize=13&amp;fontfamily=RobotoDraft%2C%20Helvetica%20Neue%2C%20Helvetica%2C%20Arial%2C%20sans-serif&amp;fontcolor=%23000000&amp;base64=true
  </code></pre>
  
  <p>eq is the querystring value we are using. In the above case it is '1%2C3'
  The url is encoded using javascript encodeURIComponent
  When I grab the above value from the query string, it's evaluated as 1,3 so I don't think there are any issues there.</p>
  
  <p>One fix I've found is to do the following:</p>
  
  
  
  <pre class="lang-cs prettyprint-override"><code>sEquation = sEquation.Replace(",", "&amp;comma;");
  </code></pre>
  
  <p>However this causes a lot of knock-on issues which would be very problematic to fix, so looking for another alternative.</p>
  
  <p>Here's the code that I'm currently running:</p>
  
  <pre class="lang-cs prettyprint-override"><code>protected void Page_Load(object sender, EventArgs e)
  {
      Response.Clear();
  
      string sEquation = Request["eq"];
      if (String.IsNullOrEmpty(sEquation))
          return;
  
      string sBase64 = Request["base64"];
      bool bBase64Output = sBase64 == "true";
  
      string sFontSize = Request["fontsize"];
      string sFontFamily = Request["fontfamily"];
      string sFontColor = Request["fontcolor"];
  
      if (string.IsNullOrEmpty(sFontSize))
      {
          sFontSize = "12";
      }
      sFontSize = Regex.Match(sFontSize, @"\d*").Value;
      float fFontSize;
      if (String.IsNullOrEmpty(sFontSize) || !float.TryParse(sFontSize, out fFontSize))
          fFontSize = 12f;
  
      //adjust font size for personal zoom level
      int iPerId = GetCurrentPersonId(null);
      double dZoom = iPerId &lt; 0 ? 1 : itPersonCache.GetEquationZoomLevel(Context, DatabaseAccess.GetDatabase(Context), iPerId, null);
      fFontSize *= (float)dZoom;
  
      Debug.Write("Generating equation image for \"" + sEquation + "\"...");
  
      //create the equation object and obtain equation bitmap...
      var oEquation = new Equation(sEquation.Replace("&amp;code", "&amp;#"), sFontFamily, fFontSize, sFontColor); //legacy replacement for old equations
      MemoryStream oStream;
      using (Bitmap oEquationBitmap = oEquation.Draw()) {
          //...encode the bitmap as png image...
          ImageCodecInfo oEncoder = GetEncoder(ImageFormat.Png);
          var oParameters = new EncoderParameters();
          var oQualityParam = new EncoderParameter(Encoder.Quality, 100L);
          oParameters.Param[0] = oQualityParam;
          oStream = new MemoryStream();
          oEquationBitmap.Save(oStream, oEncoder, oParameters);
      }
      //...then send the image as the response
      if (bBase64Output) {
          byte[] ImageBytes = oStream.ToArray();
          Response.ContentType = "text/plain";
          Response.Write(Convert.ToBase64String(ImageBytes));
          //piggyback baseline and height for equation alignment
          Response.Write(string.Format("baseline={0}height={1}zoom={2}", (int)Math.Round(oEquation.BaselineOffset, 0, MidpointRounding.AwayFromZero), oEquation.ImageHeight, dZoom));
          Debug.WriteLine(string.Format("sent via base64 text/plain ({0} bytes)", ImageBytes.Length));
      }
      else {
          Response.ContentType = "image/png";
          Response.BufferOutput = true;
          oStream.WriteTo(Response.OutputStream);
          Debug.WriteLine("sent via image/png");
      }
  }
  </code></pre>
  
  <p>Any suggestions on another way to get round this issue? Its fairly fundamental that the equation is displayed as is, so losing the comma is a big no-no.
  The base64 encoding is also a requirement.
  And the fix I mentioned above <strong><code>sEquation = sEquation.Replace(",", "&amp;comma;");</code></strong> is also a no-no given the knock on impact.
  Any help really appreciated.</p>
  
  <pre class="lang-cs prettyprint-override"><code>/// &lt;summary&gt;
      /// returns a bitmap with rendered formula
      /// &lt;/summary&gt;
      /// &lt;returns&gt;&lt;/returns&gt;
      override public Bitmap Draw()
      {
          if (oBaseSymbol == null || oBaseSymbol.fW &lt;= 0 || oBaseSymbol.fH &lt;= 0)
              return oImage;
  
          int iMargin = (int)Math.Round((BASE_MARGIN_LEFT + BASE_MARGIN_RIGHT) * oBaseSymbol.fFontSize);
          int iWidth = (int)Math.Round(oBaseSymbol.fW) + iMargin;
          oImage = new Bitmap(iWidth, (int)Math.Round(oBaseSymbol.fH));
          oGraphics = Graphics.FromImage(oImage);
          oGraphics.Clear(Color.Transparent);
  
          // Set the text antialiasing and bitmap interoplation modes (so that bitmaps that are added
          // to the equation bitmap are smoothed).
          oGraphics.TextContrast = 0;
          oGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
          oGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
  
          foreach (Symbol oSymbol in lsoSymbols) {
              if (oSymbol.sType == "Symbol" || oSymbol.sType == "Expression") {
                  float fX = oSymbol.fGX + oSymbol.oSymbolData.fPaddingLeft * oSymbol.fFontSize;
                  float fY = oSymbol.fGY;
                  // For Cambria Math symbols fY must be reduced.
                  if (oSymbol.oSymbolData.bUseMathsFont)
                      fY -= MATHS_FONT_VERTICAL_SPACE_FACTOR / 2 * oSymbol.fFontSize;
  
                  oGraphics.DrawString(oSymbol.oSymbolData.sOut, oSymbol.oFont, oSymbol.oBrush, new PointF(fX, fY));
  
  
                  if (bDrawDebugLines) {
                      oGraphics.DrawRectangle(Pens.Blue, fX, fY, fX + oSymbol.fW, fY + oSymbol.fH);
                      oGraphics.DrawLine(Pens.Red, fX, fY + oSymbol.fBaselineOffset, fX + oSymbol.fW, fY + oSymbol.fBaselineOffset);
                  }
  
  
              }
              else if (oSymbol.sType == "MText") {
                  float fX = oSymbol.fGX;
                  float fY = oSymbol.fGY;
                  oGraphics.DrawString(oSymbol.sStr, oSymbol.oFont, oSymbol.oBrush, new PointF(fX, fY));
              }
  
              foreach (Rect oRect in oSymbol.lsoRectangles) {
                  if (!String.IsNullOrEmpty(oRect.sImageToUse)) {
                      if (oRect.sImageToUse == "Dot")
                          oGraphics.DrawString(".", oSymbol.oFont, oSymbol.oBrush, new PointF(oSymbol.fGX + oRect.fX, oSymbol.fGY + oRect.fY));
                      else if (oRect.sImageToUse == "DDot")
                          oGraphics.DrawString("..", oSymbol.oFont, oSymbol.oBrush, new PointF(oSymbol.fGX + oRect.fX, oSymbol.fGY + oRect.fY));
                      else if (oRect.sImageToUse == "Tilde")
                          oGraphics.DrawString("~", oSymbol.oFont, oSymbol.oBrush, new PointF(oSymbol.fGX + oRect.fX, oSymbol.fGY + oRect.fY));
                      else if (oRect.sImageToUse == "Hat")
                          oGraphics.DrawString(HttpUtility.HtmlDecode("&amp;#94;"), oSymbol.oFont, oSymbol.oBrush, new PointF(oSymbol.fGX + oRect.fX, oSymbol.fGY + oRect.fY));
                      else
                          lock (oDrawImageLock)
                          {
                              oGraphics.DrawImage(GetImage(oRect.sImageToUse), oSymbol.fGX + oRect.fX, oSymbol.fGY + oRect.fY, oRect.fW, oRect.fH);
                          }
                  }
                  else
                      oGraphics.FillRectangle(Brushes.Black, (int)Math.Round(oSymbol.fGX + oRect.fX), (int)Math.Round(oSymbol.fGY + oRect.fY), (int)Math.Round(oRect.fW), (int)Math.Round(oRect.fH));
              }
          }
  
  
          if (bDrawDebugLines) {
              oGraphics.DrawLine(Pens.Green, 0, oBaseSymbol.fBaselineOffset, oBaseSymbol.fGX + oBaseSymbol.fW, oBaseSymbol.fBaselineOffset);
              oGraphics.DrawRectangle(Pens.Blue, 0, 0, oBaseSymbol.fW, oBaseSymbol.fH - 1);
          }
  
          return oImage;
      }
  </code></pre>