Meet us at PRINT 19. Chicago, IL. Oct. 3 - 5.
This documentation is for the old version. Go to the latest Graphics Mill docs

Drawing Text on a CMYK Bitmap

If you try to display text on a bitmap of the CMYK color space using the GdiGraphics class, the following exception will occur:

The specified pixel format is not supported.

The reason for that behavior is that the GdiGraphics does not support CMYK pixel formats. And when you try to get the GdiGraphics instance to draw a string upon, the error mentioned above occurs. To avoid this situation, you may do the following:

  1. Draw a text string on a temporary transparent RGB bitmap;
  2. Convert the temporary bitmap to one of the CMYK formats;
  3. Merge the temporary bitmap with the destination bitmap.

This approach is demonstrated below:

Visual Basic
Dim cmykImageFilname As String = "..\..\Cmyk32.jpg"
Dim resultImageFilename As String = "..\..\result.jpg"

' Load source CMYK bitmap.
Dim cmykBitmap As New Aurigma.GraphicsMill.Bitmap(cmykImageFilname)

' Configure the text settings.
Dim str As String = "Aurigma1"
Dim font As New System.Drawing.Font("Arial", 24)
Dim g As System.Drawing.Graphics = System.Drawing.Graphics.FromHwnd(IntPtr.Zero)
Dim size As System.Drawing.SizeF = g.MeasureString(str, font)
Dim brush As New System.Drawing.SolidBrush(System.Drawing.Color.Red)

' Create temporary 32bpp ARGB bitmap and draw the string on it.
Dim tempBitmap As New Aurigma.GraphicsMill.Bitmap(Int(size.Width), Int(size.Height), _
    Aurigma.GraphicsMill.PixelFormat.Format32bppArgb)
Dim graphics As System.Drawing.Graphics = _
    System.Drawing.Graphics.FromImage(tempBitmap.ToGdiplusBitmapDirectly())

Try
    graphics.DrawString(str, font, brush, 0, 0)
Finally
    graphics.Dispose()
End Try

' Convert temporary bitmap to the CMYK pixel format and then combine it with the destination bitmap.
tempBitmap.ColorManagement.ConvertToContinuous(Aurigma.GraphicsMill.ColorSpace.Cmyk, _
    tempBitmap.HasAlpha, tempBitmap.IsExtended)
tempBitmap.Draw(cmykBitmap, 10, 10, tempBitmap.Width, tempBitmap.Height, _
    Aurigma.GraphicsMill.Transforms.CombineMode.Alpha, 1.0F, _
    Aurigma.GraphicsMill.Transforms.InterpolationMode.LowQuality)

cmykBitmap.Save(resultImageFilename)

tempBitmap.Dispose()
cmykBitmap.Dispose()
C#
string cmykImageFilname = @"..\..\Cmyk32.jpg";
string resultImageFilename = @"..\..\result.jpg";

// Load source CMYK bitmap.
Aurigma.GraphicsMill.Bitmap cmykBitmap = new Aurigma.GraphicsMill.Bitmap(cmykImageFilname);

// Configure the text settings.
string str = "Aurigma1";
System.Drawing.Font font = new System.Drawing.Font("Arial", 24);
System.Drawing.Graphics g = System.Drawing.Graphics.FromHwnd(IntPtr.Zero);
System.Drawing.SizeF size = g.MeasureString(str, font);
System.Drawing.SolidBrush brush = new System.Drawing.SolidBrush(System.Drawing.Color.Red);

// Create temporary 32bpp ARGB bitmap and draw the string on it.
Aurigma.GraphicsMill.Bitmap tempBitmap = new
      Aurigma.GraphicsMill.Bitmap((int)size.Width, (int)size.Height, 
      Aurigma.GraphicsMill.PixelFormat.Format32bppArgb);
System.Drawing.Graphics graphics =
      System.Drawing.Graphics.FromImage(tempBitmap.ToGdiplusBitmapDirectly());
try
{
    graphics.DrawString(str, font, brush, 0, 0);
}
finally
{
    graphics.Dispose();
}

// Convert temporary bitmap to the CMYK pixel format and then combine it with the destination bitmap.
tempBitmap.ColorManagement.ConvertToContinuous(Aurigma.GraphicsMill.ColorSpace.Cmyk,
      tempBitmap.HasAlpha, tempBitmap.IsExtended);
tempBitmap.Draw(cmykBitmap, 10, 10, tempBitmap.Width, tempBitmap.Height,
      Aurigma.GraphicsMill.Transforms.CombineMode.Alpha, 1.0f,
      Aurigma.GraphicsMill.Transforms.InterpolationMode.LowQuality);

cmykBitmap.Save(resultImageFilename);

tempBitmap.Dispose();
cmykBitmap.Dispose();

As you can see in this sample the string is drawn using an RGB color. But what if you want to draw a string using a CMYK color value? In this case you will need to either perform a color conversion (from CMYK to RGB) before drawing the text, or, if you need to keep the exact CMYK value, use a completely different approach to the problem.

The idea of this approach is to create an empty ACMYK bitmap filled with the necessary color, and then "cut through" the text in the alpha channel. After that the bitmaps will be merged. However, this approach has its own shortcomings:

  • You may find the text output quality worse than when using the standard approach (though that is not necessarily so).
  • If the text string is considerably large, it will result in a noticeable memory footprint.

Here is a code sample demonstrating this approach:

Visual Basic
Dim cmykImageFilname As String = "..\..\Cmyk32.jpg"
Dim resultImageFilename As String = "..\..\result.jpg"

' Load source CMYK bitmap.
Dim cmykBitmap As New Aurigma.GraphicsMill.Bitmap(cmykImageFilname)

' Configure the text settings.
Dim str As String = "Aurigma2"
Dim font As New System.Drawing.Font("Arial", 36)
Dim g As System.Drawing.Graphics = System.Drawing.Graphics.FromHwnd(IntPtr.Zero)
Dim size As System.Drawing.SizeF = g.MeasureString(str, font)

' Set the text color.
Dim textColor As Aurigma.GraphicsMill.CmykColor = _
    Aurigma.GraphicsMill.CmykColor.FromCmyk(128, 12, 55, 25)

' Create a solid CMYK bitmap filled with the text color and a mask where we will
' "cut through" the text. The mask must be an 8-bit GrayScale bitmap, but if we try
' to draw anything on such bitmap no antialiasing will be applied. That's why we
' create a 24-bit RGB bitmap and convert it to GrayScale later.
Dim tempBitmap As New Aurigma.GraphicsMill.Bitmap(textColor, _
    Int(size.Width), Int(size.Height), Aurigma.GraphicsMill.PixelFormat.Format40bppAcmyk)
Dim maskBitmap As New Aurigma.GraphicsMill.Bitmap(Int(size.Width), _
    Int(size.Height), Aurigma.GraphicsMill.PixelFormat.Format24bppRgb)

' "Cut through" the text in the mask.
Dim graphics As Aurigma.GraphicsMill.Drawing.GdiGraphics = maskBitmap.GetGdiGraphics()
graphics.DrawString(str, font, _
    New Aurigma.GraphicsMill.Drawing.SolidBrush(Aurigma.GraphicsMill.RgbColor.White), _
    New System.Drawing.Point(0, 0))

maskBitmap.ColorManagement.ConvertToContinuous(Aurigma.GraphicsMill.ColorSpace.GrayScale, _
    False, False)

' Replace the alpha channel with the mask.
tempBitmap.Channels(Aurigma.GraphicsMill.ColorChannel.Alpha) = maskBitmap
' Merge the text with the bitmap.
tempBitmap.Draw(cmykBitmap, 20, 20, 0, 0, Aurigma.GraphicsMill.Transforms.CombineMode.Alpha, _
          1, Aurigma.GraphicsMill.Transforms.InterpolationMode.HighQuality)

cmykBitmap.Save(resultImageFilename)

tempBitmap.Dispose()
cmykBitmap.Dispose()
C#
string cmykImageFilname = @"..\..\Cmyk32.jpg";
string resultImageFilename = @"..\..\result.jpg";

// Load source CMYK bitmap.
Aurigma.GraphicsMill.Bitmap cmykBitmap = new Aurigma.GraphicsMill.Bitmap(cmykImageFilname);

// Configure the text settings.
string str = "Aurigma2";
System.Drawing.Font font = new System.Drawing.Font("Arial", 36);
System.Drawing.Graphics g = System.Drawing.Graphics.FromHwnd(IntPtr.Zero);
System.Drawing.SizeF size = g.MeasureString(str, font);

// Set the text color.
Aurigma.GraphicsMill.CmykColor textColor = 
    Aurigma.GraphicsMill.CmykColor.FromCmyk(128, 12, 55, 25);

// Create a solid CMYK bitmap filled with the text color and a mask where we will
// "cut through" the text. The mask must be an 8-bit GrayScale bitmap, but if we try
// to draw anything on such bitmap no antialiasing will be applied. That's why we
// create a 24-bit RGB bitmap and convert it to GrayScale later.
Aurigma.GraphicsMill.Bitmap tempBitmap = new Aurigma.GraphicsMill.Bitmap(textColor,
      (int)size.Width, (int)size.Height, Aurigma.GraphicsMill.PixelFormat.Format40bppAcmyk);
Aurigma.GraphicsMill.Bitmap maskBitmap = new Aurigma.GraphicsMill.Bitmap((int)size.Width,
      (int)size.Height, Aurigma.GraphicsMill.PixelFormat.Format24bppRgb);

// "Cut through" the text in the mask.
Aurigma.GraphicsMill.Drawing.GdiGraphics graphics = maskBitmap.GetGdiGraphics();
graphics.DrawString(str, font,
      new Aurigma.GraphicsMill.Drawing.SolidBrush(Aurigma.GraphicsMill.RgbColor.White),
      new System.Drawing.Point(0, 0));
maskBitmap.ColorManagement.ConvertToContinuous(Aurigma.GraphicsMill.ColorSpace.GrayScale,
      false, false);

// Replace the alpha channel with the mask.
tempBitmap.Channels[Aurigma.GraphicsMill.ColorChannel.Alpha] = maskBitmap;

// Merge the text with the bitmap.
tempBitmap.Draw(cmykBitmap, 20, 20, 0, 0, Aurigma.GraphicsMill.Transforms.CombineMode.Alpha,
      1, Aurigma.GraphicsMill.Transforms.InterpolationMode.HighQuality);

cmykBitmap.Save(resultImageFilename);

tempBitmap.Dispose();
cmykBitmap.Dispose();

See Also

Reference

Manual