I'm working on creating a new class to manipulate images and I just can't seem to get the speed I'm looking for out of it. I feel like calling g.DrawImage()
is just taking longer than it should.
When using this same process set up in a project using the LeadTools SDK I use a byte copy like method that copies each row of pixels. That yields much faster results.
Note: I have a simple LogDebug() function (I know is solid) that keeps track of the ticks to do some bench testing. I would like to not focus on that and focus on the different methods of coping bitmap data and speed.
Test Results
When setting headerHeight = 0;
(not adding extra white space to the top of the original image) I get the following results.
/*
Creating text on image pages.
Added text to image 1. (920ms)
Added text to image 2. (303ms)
Added text to image 3. (368ms)
Saved new image. (307ms)
Total time to generate text on image: 00h:00m:01s:908ms.
*/
When setting headerHeight = 100;
(adding extra white space to the top of the original image) I get the following results.
/*
Creating text on image pages.
Added text to image 1. (2394ms)
Added text to image 2. (438ms)
Added text to image 3. (441ms)
Saved new image. (314ms)
Total time to generate stamp: 00h:00m:03s:598ms.
*/
Source
private void TestCreateTextOnImage()
{
LogDebug("Creating text on image pages.", false);
for (int p = 1; p <= 3; p++)
{
AddTextToImage(p);
LogDebug($"Added text to image {p}.");
}
SaveImage();
LogDebug("Saved new image.");
LogDebug("Total time to generate text on image: [TotalTicks].");
}
// Test adding text to an image
List<Image> _imageCachedPages = new List<Image>();
public void AddTextToImage(int pageNum)
{
string fontName = "Verdana";
int fontSize = 60;
// Cache the 3 page image
Image imageCached = Image.FromFile(@"c:\test\3_page_image.tif");
// Select page 2 of the three page image
imageCached.SelectActiveFrame(FrameDimension.Page, pageNum - 1);
// Test add text
int headerHeight = 0;
// Also test adding extra white space (expand image canvas)
headerHeight = 100;
// Create new image that will be the bottom layer (blank canvas)
Bitmap annotatedImage = new Bitmap(
imageCached,
new Size(
imageCached.Width,
imageCached.Height + headerHeight
)
);
annotatedImage.SetResolution(imageCached.HorizontalResolution, imageCached.VerticalResolution);
using (Graphics g = Graphics.FromImage(annotatedImage))
{
// Paint canvas white
Rectangle r = new Rectangle(0, 0, imageCached.Width, imageCached.Height);
g.FillRectangle(Brushes.White, r);
// Paint original image on top of new canvas
g.DrawImage(imageCached, new Point(0, headerHeight));
// The code I used with the LeadTools SDK that seems much faster
/*
byte[] buffer = new byte[srcImage.BytesPerLine];
for (int yH = 0; yH < srcImage.Height; yH++)
{
srcImage.GetRow(yH, buffer, 0, buffer.Length);
annotatedImage.SetRow(yH + headerHeight, buffer, 0, buffer.Length);
}
*/
// Create the font objects
FontFamily fontFamily = new FontFamily(fontName);
Font font = new Font(fontFamily, fontSize, FontStyle.Regular, GraphicsUnit.Pixel);
// Create a rect to define the position and size of the annotated text
RectangleF positionRect = new RectangleF(20, 20, 500, 500);
// Draw column text
g.DrawString("Sample Text\nLine 2", font, Brushes.Black, positionRect);
}
// Save the image to the new image's page collection at the correct page position
while (_imageCachedPages.Count < pageNum)
_imageCachedPages.Add(null);
_imageCachedPages[pageNum - 1] = annotatedImage;
}
I think a large part of your slowness is related to the fact that you are effectively drawing the image twice:
Bitmap annotatedImage = new Bitmap(
imageCached,
new Size(
imageCached.Width,
imageCached.Height + headerHeight
)
);
then at:
g.DrawImage(imageCached, new Point(0, headerHeight));
I suspect if you changed the former to:
Bitmap annotatedImage = new Bitmap(imageCached.Width, imageCached.Height + headerHeight);
the code will run substantially faster.