|
|
Home » U++ Library support » Draw, Display, Images, Bitmaps, Icons » Draw::DrawImageOp optimization bug
Draw::DrawImageOp optimization bug [message #19334] |
Thu, 27 November 2008 13:52  |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
Hi,
There is a problem when printing large images. Disabling the "if((cx > 2000 || cy > 2000) ..." -triggered image printing optimization in Draw.cpp / Draw::DrawImageOp(), makes the problem disappear.
The optimized printout reveals narrow white uncovered gaps (both horizontal and vertical) between rendered blocks:

This can be verified when printing images with a high resolution printer or just with "Microsoft XPS Document Writer". The XPS document, when viewed with Microsoft XPS Viewer shows clearly the problem.
Also, when printing to a color laser printer (Xerox Phaser 6200), the coloring of the printed image becomes uneven along the optimized blocks. This also is fixed when printing without the optimization.
// Tom
|
|
|
|
Re: Draw::DrawImageOp optimization bug [message #19350 is a reply to message #19349] |
Fri, 28 November 2008 10:23   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
I wrote a simple test case that can be used to visualize the problem easily when printing to e.g. Microsoft XPS Document Writer.
#include <CtrlLib/CtrlLib.h>
using namespace Upp;
class Testcase2 : public TopWindow{
public:
typedef Testcase2 CLASSNAME;
Testcase2(){
Sizeable();
MinimizeBox();
MaximizeBox();
BackPaint();
}
void drawimage(Draw &draw){
Size sz;
if(draw.IsPrinter()) sz=draw.GetPagePixels();
else sz=GetSize();
ImageBuffer ib(sz.cx,sz.cy);
for(int y=0;y<sz.cy;y++){
for(int x=0;x<sz.cx;x++){
ib[y][x]=(RGBA)Color((16*y/sz.cy)<<4,(16*y/sz.cy)<<4,(16*x/sz.cx)<<4);
}
}
Rect rect=draw.GetClip();
draw.DrawRect(rect,Color(255,255,255));
Image img(ib);
draw.DrawImage(0,0,img);
if(!draw.IsPrinter()){
draw.DrawText(10,10,"Press 'P' to print...",StdFont(),Color(255,255,255));
draw.DrawText(10,30,"(This really drains your ink/toner cartridge, so try e.g. Microsoft XPS Document Writer.)",StdFont(),Color(255,255,255));
}
}
void print(){
PrinterJob *job=new PrinterJob();
if(job){
if(job->Execute()){
Draw &draw=job->GetDraw();
draw.StartPage();
drawimage(draw);
draw.EndPage();
}
delete job;
}
}
virtual void Paint(Draw &draw){
drawimage(draw);
}
bool Key(dword key, int count){
switch(key){
case K_P:
print();
return true;
}
return false;
}
};
GUI_APP_MAIN
{
Testcase2().Run();
}
// Tom
|
|
|
|
|
|
Re: Draw::DrawImageOp optimization bug [message #19357 is a reply to message #19354] |
Fri, 28 November 2008 13:54   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
Still off-topic, but even more so: I started writing applications with C++ in 1988 and for years I often ended up with stack overflow whenever I attempted to use local variables from my classes. So, I learned my lesson and started to use pointers and new/delete instead. A lot of time has passed along the way and this problem with local variables and stack overflows may well have disappeared altogether, but I seem to be stuck with my old habits. Well, maybe I will learn over the next decade or so...
// Tom
|
|
|
|
Re: Draw::DrawImageOp optimization bug [message #19362 is a reply to message #19358] |
Fri, 28 November 2008 21:02   |
 |
mirek
Messages: 14257 Registered: November 2005
|
Ultimate Member |
|
|
Well, I have spent last 4 hours with this problem and I really do not know what to think....
See this:
#include <CtrlLib/CtrlLib.h>
using namespace Upp;
class Testcase2 : public TopWindow{
public:
typedef Testcase2 CLASSNAME;
Testcase2(){
Sizeable();
MinimizeBox();
MaximizeBox();
BackPaint();
}
Image MakeImage2(Size sz) const {
ImageBuffer ib(sz.cx / 3, sz.cy / 3);
Fill(ib, LtBlue(), ib.GetLength());
const Color c[] = { LtBlue() };
for(int y = 0; y < ib.GetWidth(); y++) {
for(int x = 0; x < ib.GetHeight(); x++)
ib[x][y] = c[2 * (x > ib.GetHeight() / 2) + (y > ib.GetWidth() / 2)];
}
return ib;
}
Image MakeImage(Size sz) const {
ImageDraw iw(sz / 3);
iw.DrawRect(sz / 3, Blue);
iw.DrawText(0, 0, "O", Roman(sz.cy / 3).Italic(), Red());
return iw;
}
Image MakeImage1(Size sz) const {
ImageBuffer ib(sz);
for(int y=0;y<sz.cy;y++){
for(int x=0;x<sz.cx;x++){
ib[y][x]=(RGBA)Color((16*y/sz.cy)<<4,(16*y/sz.cy)<<4,(16*x/sz.cx)<<4);
}
}
return ib;
}
void print(){
}
virtual void Paint(Draw &w){
Size sz = GetSize();
w.DrawRect(GetSize(), White);
w.DrawImage(0, 0, MakeImage(GetSize()));
w.DrawText(10,500,"Press 'P' to print image, 'R' to print rectangle test, 'C' to another test...");
w.DrawText(10,530,"(This really drains your ink/toner cartridge, so try e.g. Microsoft XPS Document Writer.)");
}
bool Key(dword key, int count){
PrinterJob job;
switch(key){
case K_P:
if(job.Execute()){
Draw &draw = job;
draw.StartPage();
draw.DrawImage(0, 0, MakeImage(draw.GetPagePixels()));
draw.EndPage();
}
return true;
case K_R:
if(job.Execute()){
Draw &draw = job;
draw.StartPage();
bool flag = false;
for(int y = 0; y < 100; y++)
for(int x = 0; x < 100; x++) {
draw.DrawRect(16 * x, 16 * y, 16, 16, flag ? Blue : Red);
if((Random() & 31) == 0)
flag = !flag;
}
draw.EndPage();
}
return true;
case K_C:
if(job.Execute()){
Draw &draw = job;
draw.StartPage();
for(int y = 0; y < 100; y++)
for(int x = 0; x < 100; x++)
draw.DrawRect(16 * x, 16 * y, 16, 16, Blue);
draw.EndPage();
}
return true;
}
return false;
}
};
GUI_APP_MAIN
{
Testcase2().Run();
}
Now interesting things happen when you press R or C.
These try to emulate the compression issue. When you do R, you have those line artifacts, but C seems without the issue - and only thing that has changed is the color.
Is not it really weird? (Note that it is not even related to Image).
It can also be seen with P... The areas that are "full line" are OK.
Well, I have also tried to mitigate the issue by "overpainting" rectangle (adding to height/width), but interestigly that seems to have produced other issues.
OK, enough for today, next tomorrow. We really need this working BTW.
Mirek
|
|
|
Re: Draw::DrawImageOp optimization bug [message #19368 is a reply to message #19362] |
Sat, 29 November 2008 12:54   |
 |
mirek
Messages: 14257 Registered: November 2005
|
Ultimate Member |
|
|
luzr wrote on Fri, 28 November 2008 15:02 |
Well, I have also tried to mitigate the issue by "overpainting" rectangle (adding to height/width), but interestigly that seems to have produced other issues.
|
- just try to extend values in DrawRect
draw.DrawRect(16 * x, 16 * y, 19, 19, flag ? Blue : Red);
Frankly, I am in dead end. I believe that the whole issue is just a driver bug, and I do not see any reasonable workaround.
Mirek
|
|
|
Re: Draw::DrawImageOp optimization bug [message #19401 is a reply to message #19368] |
Mon, 01 December 2008 11:25   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
I looked into this problem from another aspect: I shrinked the rectangle by one pixel from each edge. This proved that in the RLE code the edges of the rectangles and sub-images are exactly accurate. What happens in XPS, is that the edges show sub-pixel level inaccuracies that are internal to the XPS. This can be very accurately visualized in XPS Viewer using 5000% zooming. So, it is not U++ fault. XPS Viewer also internally softens the rasters when zooming in, and then another set of problems arise with the rectangles and sub-images: They do not quite fit together with soft and sharp edges side-by-side.
On the other hand, the unrelated problem with uneven colors in Xerox Phaser 6200, might have something to do with color spaces being different for images and vector elements causing weird color effects. I have no proof of this, but still, the printout gets corrected when this optimization is commented out.
I suggest an option flag -- maybe even enabled by default -- for skipping the optimization for large images.
// Tom
|
|
|
Re: Draw::DrawImageOp optimization bug [message #19402 is a reply to message #19401] |
Mon, 01 December 2008 12:12   |
 |
mirek
Messages: 14257 Registered: November 2005
|
Ultimate Member |
|
|
Tom1 wrote on Mon, 01 December 2008 05:25 | I looked into this problem from another aspect: I shrinked the rectangle by one pixel from each edge. This proved that in the RLE code the edges of the rectangles and sub-images are exactly accurate. What happens in XPS, is that the edges show sub-pixel level inaccuracies that are internal to the XPS. This can be very accurately visualized in XPS Viewer using 5000% zooming. So, it is not U++ fault. XPS Viewer also internally softens the rasters when zooming in, and then another set of problems arise with the rectangles and sub-images: They do not quite fit together with soft and sharp edges side-by-side.
|
OK, that would mean we should attempt for "overpaint" solution and ignore those weird artifacts?
Quote: |
On the other hand, the unrelated problem with uneven colors in Xerox Phaser 6200, might have something to do with color spaces being different for images and vector elements causing weird color effects. I have no proof of this, but still, the printout gets corrected when this optimization is commented out.
|
Ooops.
Quote: |
I suggest an option flag -- maybe even enabled by default -- for skipping the optimization for large images.
|
Well, that is the last resort solution...
BTW, at least, we should not be afraid to optimize white areas, correct? 
Mirek
|
|
|
|
Re: Draw::DrawImageOp optimization bug [message #19404 is a reply to message #19402] |
Mon, 01 December 2008 12:49   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
After seeing all this happening with basically simple rasters and rectangles, I'm not quite sure anymore what really will happen if even the white areas get optimized... How do they cover the stuff drawn behind those areas to be covered with white?
Of course, if drawing the optimized image starts with a single white DrawRectOp() covering the entire image rect, and then continues by adding the non-white sub-images on top of that should work... but only for OPAQUE pictures.
UPDATE:
Quote: |
BTW, it is interesting that those rects are being painted using PatBlt (basically, a pixel-pushing api).
|
Correct, but: PatBlt uses current brush just like Rectangle and other vector functions with fill capability, so the color mapping mechanism must be the same.
BTW: Is PatBlt more efficient that Rectangle?
// Tom
[Updated on: Mon, 01 December 2008 13:00] Report message to a moderator
|
|
|
Re: Draw::DrawImageOp optimization bug [message #19405 is a reply to message #19404] |
Mon, 01 December 2008 12:57   |
 |
mirek
Messages: 14257 Registered: November 2005
|
Ultimate Member |
|
|
Tom1 wrote on Mon, 01 December 2008 06:49 | After seeing all this happening with basically simple rasters and rectangles, I'm not quite sure anymore what really will happen if even the white areas get optimized... How do they cover the stuff drawn behind those areas to be covered with white?
Of course, if drawing the optimized image starts with a single white DrawRectOp() covering the entire image rect, and then continues by adding the non-white sub-images on top of that should work... but only for OPAQUE pictures.
// Tom
|
Just a sidenote: I must see stubborn desperately trying to keep this optimization, but:
- some of my existing applications would have troubles without it, this is essential to e.g. printing .jpges directly to the printer, without the need of rescaling them to 500MB.
- this concept plays an important role in the future, when we will need to print svg pictures. I expect that this will work very well with most bussines oriented graphivs.
I now believe that we can handle artifacts issue, at least on printers.
So the problem now is the color mismatch.. 
Mirek
|
|
|
Re: Draw::DrawImageOp optimization bug [message #19406 is a reply to message #19404] |
Mon, 01 December 2008 13:12   |
 |
mirek
Messages: 14257 Registered: November 2005
|
Ultimate Member |
|
|
Tom1 wrote on Mon, 01 December 2008 06:49 |
Of course, if drawing the optimized image starts with a single white DrawRectOp() covering the entire image rect, and then continues by adding the non-white sub-images on top of that should work... but only for OPAQUE pictures.
|
I would not hope too much that any existing printer driver can really handle non-OPAQUE picture, meanwhile, it should be simple to avoid optimization for them too...
Quote: |
BTW, it is interesting that those rects are being painted using PatBlt (basically, a pixel-pushing api).
|
Correct, but: PatBlt uses current brush just like Rectangle and other vector functions with fill capability, so the color mapping mechanism must be the same.
[/quote]
Yes, likely yes.
Quote: |
BTW: Is PatBlt more efficient that Rectangle?
|
I do not believe so. But AFAIK, they are rounded to physical resolution differently. In fact, that is most likely the source of our problem.
Mirek
|
|
|
|
Re: Draw::DrawImageOp optimization bug [message #19408 is a reply to message #19405] |
Mon, 01 December 2008 13:50   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
luzr wrote on Mon, 01 December 2008 13:57 |
Just a sidenote: I must see stubborn desperately trying to keep this optimization, but:
- some of my existing applications would have troubles without it, this is essential to e.g. printing .jpges directly to the printer, without the need of rescaling them to 500MB.
- this concept plays an important role in the future, when we will need to print svg pictures. I expect that this will work very well with most bussines oriented graphivs.
I now believe that we can handle artifacts issue, at least on printers.
So the problem now is the color mismatch.. 
Mirek
|
No need to apologize, you're the chief -- not me.
I faced the same 'oversized printout' problem with images and went around it using ::StretchDIBits() GDI API. This effectively shrinked the amount of data transferred to the printer. I guess there are very few printers really capable of printing 24 or 32 bit colors at the full resolution so the colors visible to the eye are really sums of many adjacent pixels in both horizontal and vertical directions. Therefore, I use lower resolution for color and gray scale images to be transferred to the printer and print only the vector graphics at the full resolution on top of that.
I'm really dependent on this for many of my applications, but I have been able to do it without modifications U++ itself, so I have not been pressuring you to take it in. If it was to be integrated to U++ Draw::, I would prefer an option flag for natively stretched images, instead of U++ based pre-stretching when expanding of images was needed.
// Tom
|
|
|
|
Re: Draw::DrawImageOp optimization bug [message #19410 is a reply to message #19407] |
Mon, 01 December 2008 14:37   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
I made a simple test drawing two adjacent 100x100 dots squares filled with the same Color(180,180,0). The first one was an Image and the second was a Rectangle.
For Windows Vista with standard printer driver: I can confirm that the colors do not match on Xerox Phaser 6200. Not even close. The image is much lighter than the rectangle. I tried with ICM (Image color management) enabled and disabled, and with other options: No change.
For Windows XP it first appeared that nothing is different compared to Vista, but after changing a parameter (Color Correction: Press Match = Commercial Press), I got the colors finally to match. (This parameter can not be set for Windows Vista though, so no luck there.)
To sum it up, the color space may indeed be different for raster and vector entities within the same device context. Not a very nice feature from the optimization point of view.
// Tom
|
|
|
Goto Forum:
Current Time: Sun May 11 19:59:26 CEST 2025
Total time taken to generate the page: 0.00666 seconds
|
|
|