Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
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 Go to next message
Tom1
Messages: 1212
Registered: March 2007
Senior 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:

index.php?t=getfile&id=1500&private=0

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 #19349 is a reply to message #19334] Fri, 28 November 2008 08:56 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Tom1 wrote on Thu, 27 November 2008 07:52

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:

index.php?t=getfile&id=1500&private=0

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



Thanks. Looks like we need to work a bit on this.

BTW, can you upload the testing image (and maybe the whole testcase) somewhare?

Mirek
Re: Draw::DrawImageOp optimization bug [message #19350 is a reply to message #19349] Fri, 28 November 2008 10:23 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior 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 #19352 is a reply to message #19350] Fri, 28 November 2008 13:15 Go to previous messageGo to next message
rylek is currently offline  rylek
Messages: 79
Registered: November 2005
Member
Hi there!

The 2000 x 2000 block limitation is a problematic old hack I used long ago when I had trouble with GDI processing larger areas at once. Some of it was W98-related and is probably long gone, but a few years ago I encountered the same problem when printing a very large raster-based drawing on an A0 cylinder plotter with not much memory where without piecewise upload the plotter wouldn't print anything at all. Some expertise would evidently help here and the blit routine should be if-ed properly perhaps based on some properties of the output device and/or OS version.

Regards

Tomas
Re: Draw::DrawImageOp optimization bug [message #19353 is a reply to message #19352] Fri, 28 November 2008 13:27 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
rylek wrote on Fri, 28 November 2008 07:15

Hi there!

The 2000 x 2000 block limitation is a problematic old hack I used long ago when I had trouble with GDI processing larger areas at once.



Actually, I am afraid you are not up-to-date about this one...

This is not the "old Image code" (although it can fix the same problem as byproduct).

Current DrawImage really does something new, the RLE compression. Also, but splitting the process to bands, it should help with memory consumption - e.g. imagine printing some documentation from RichText, where screenshots are usually rescaled to much bigger size. Banding pushes them in bands, means we do not need the memory for the "big" results.

And more, "RLE compression" (detecting uniform color blocks) has the potential to reduce the memory footprint even in the printer.

Mirek
Re: Draw::DrawImageOp optimization bug [message #19354 is a reply to message #19350] Fri, 28 November 2008 13:29 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Tom1 wrote on Fri, 28 November 2008 04:23


void print(){
PrinterJob *job=new PrinterJob();
if(job){
if(job->Execute()){
Draw &draw=job->GetDraw();
draw.StartPage();
drawimage(draw);
draw.EndPage();
}
delete job;
}
}



Off-topic: Why the 'new' here?

In U++, never use 'new' unless you have a VERY good reason to do so - either you are doing some too low-level or you need 'naked' polymorphy. But as for polymorphy, you can also use 'encapsulated' form with One...

Mirek
Re: Draw::DrawImageOp optimization bug [message #19357 is a reply to message #19354] Fri, 28 November 2008 13:54 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior 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 #19358 is a reply to message #19357] Fri, 28 November 2008 14:27 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Tom1 wrote on Fri, 28 November 2008 07:54

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


I can understand that... However, those old habits do separate you from the main advantage of C++/U++ - automated resource management...

Mirek
Re: Draw::DrawImageOp optimization bug [message #19362 is a reply to message #19358] Fri, 28 November 2008 21:02 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
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 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
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 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior 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 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
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? Smile

Mirek
Re: Draw::DrawImageOp optimization bug [message #19403 is a reply to message #19401] Mon, 01 December 2008 12:41 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Tom1 wrote on Mon, 01 December 2008 05:25


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.



BTW, it is interesting that those rects are being painted using PatBlt (basically, a pixel-pushing api).

Mirek
Re: Draw::DrawImageOp optimization bug [message #19404 is a reply to message #19402] Mon, 01 December 2008 12:49 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior 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 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
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.. Sad

Mirek
Re: Draw::DrawImageOp optimization bug [message #19406 is a reply to message #19404] Mon, 01 December 2008 13:12 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
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 #19407 is a reply to message #19401] Mon, 01 December 2008 13:14 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Tom1 wrote on Mon, 01 December 2008 05:25


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.



Something simple to try: Create uniform color Image (e.g. using CreateImage(Size sz, Color color) then print it alongside the Rect with the same color.

Mirek
Re: Draw::DrawImageOp optimization bug [message #19408 is a reply to message #19405] Mon, 01 December 2008 13:50 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior 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.. Sad

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 #19409 is a reply to message #19408] Mon, 01 December 2008 14:25 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Tom1 wrote on Mon, 01 December 2008 07:50


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.



Those JPEGs are 600dpi scans of A4 pages...Smile

Mirek
Re: Draw::DrawImageOp optimization bug [message #19410 is a reply to message #19407] Mon, 01 December 2008 14:37 Go to previous messageGo to previous message
Tom1
Messages: 1212
Registered: March 2007
Senior 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

Previous Topic: Extensions to Draw...Ops
Next Topic: Compile package with iml file problem!
Goto Forum:
  


Current Time: Thu Mar 28 16:12:33 CET 2024

Total time taken to generate the page: 0.01139 seconds