I made an invoice that has a listview on the bottom to list all of the line items. This can run over the one page mark so I overloaded the DocumentPaginator class to allow for me to print multiple pages. However, sometimes it cuts the page in the middle of a line of the listview. I found an article that uses a bitmap of the wpf control, then checks the color of pixels of a line to determine if there is whitespace or data (code below). When I make my control into a bitmap though, the spacing and line height is different than when I print the wpf control as an xps or to the printer. Any other ideas out there on how to intelligently break pages or get the bitmap to match the xps?
private void GetGoodCut()
{
int goodCut = _lastCut;
int lastNumber = 0;
int numberCount = 1;
// At most, it will take 32 pixel lines to find a white space
for (int i = 0; i < 32; i++)
{
int number = rowPixelWhiteCount(_bitmap, goodCut);
goodCut--;
if (number == lastNumber)
{
numberCount++;
// White space count between LV lines is 12
if (numberCount == 12)
{
lastNumber = i - 6;
break;
}
}
else
{
// If we started inside a white space, can break if starting before/at middle of the white space
if (numberCount > 5)
{
lastNumber = i - 6;
break;
}
numberCount = 1;
}
lastNumber = number;
}
_lastCut -= lastNumber;
}
private int rowPixelWhiteCount(System.Drawing.Bitmap bmp, int row)
{
int colorCount = 0;
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
int stride = bmpData.Stride;
IntPtr firstPixelInImage = bmpData.Scan0;
unsafe
{
byte* p = (byte*)(void*)firstPixelInImage;
p += stride * row; // find starting pixel of the specified row
for (int column = 0; column < bmp.Width; column++)
{
// Printing in black/white, look for non-black pixels
byte blue = p[0];
byte red = p[1];
byte green = p[3];
if (blue > 0 && red > 0 && green > 0)
colorCount++;
// go to next pixel
p += 3;
}
}
bmp.UnlockBits(bmpData);
count.Add(colorCount);
return colorCount;
}