Strange DrvStretchBlt/EngStretchBlt Behaviour

I have a monolithic user mode print driver which has hooked most calls.
Everything seems to be working fine, except for this one scenario involving DrvStretchBlt. A little architectural info:

The driver uses banding, and implements DrvStartbanding, DrvQueryPerBandInfo, DrvNextBand.

The driver forces the GDI to send each page twice.

On the first pass the driver captures all of the vector information from DrvStrokePath, etc, at a resolution of 1000 dpi. During this pass, calls into DrvStretchBlt, etc, are analyzed to collect the areas that it intends to draw to, but no drawing is done.

On the second pass, a small bitmap is created at a lower resolution (300 dpi) which is just large enough to accommodate all of the raster drawing calls.

During the second pass, calls to DrvStrokePath, etc., are ignored, and calls to DrvStretchBlt, etc., are punted to the GDI to do the actual drawing on the lower res SURFOBJ.

All functions work fine. The driver produces valid output. There is one strange situation with DrvStretchBlt.

I am primarily printing from CorelDraw. Here is a description of a call into DrvStretchBlt that works, and then a variation which doesn’t.

If I make a CorelDraw page that is, say, 8.5"w , 11"h, and import a photograph that is sized on the page to, say, 5"w , 3"h. Let’s say the coordinate of the top left corner of the photo is 2" from left, 2" from top.

On the first pass, DrvStretchBlt is called. It tells me that I have a source SURFOBJ which is 5000w , 3000h (1000 dpi) which needs to be drawn on my 8500w , 11000h (1000 dpi) destination SURFOBJ at a top left corner of 2000x, 2000y (1000 dpi).
I don’t do the drawing. I record the size of the surface I will need for second pass.

On the second pass, I tell the GDI to scale the page to 300 dpi, and I create a small SURFOBJ just large enough for the actual drawing area: 5"w , 3"h at 300 dpi = 1500w, 900h.

During the second pass, DrvStretchBlt is called, and it tells me that I need to draw the incoming source SURFOBJ, which is 1500w x 900h (300 dpi) onto my destination SURFOBJ at coordinate 600x, 600y (300 dpi).

Now, at this point, I don’t have a 300 dpi SURFOBJ for the whole page 8.5" x 11" page, which would be 2550w , 3300h. Instead, I have a small SURFOBJ which is only 1500h, 900h, which is just large enough to draw on. Since the area is a subset of the entire page, I need to subtract the x,y of my subset area from the incoming destination x,y to draw to. The coordinate of my subset SURFOBJ is 600x, 600y, so subtracting that from the incoming destination coordinate gives a new destination coordinate of 0,0.

So the call is punted to EngStretchBlt, suing the same arguments that were passed into DrvStretchBlt. The only changed arguments are these: the incoming destination SURFOBJ is replaced with the smaller subset SURFOBJ, and the incoming destination x,y is replaced with the corrected x,y for the subset.

The above scenario works great. EngStretchBlt returns success, and the results look great.

Now the modification problem:

If I keep this same job in CorelDraw, but grab the CorelDraw erase tool, and erase a portion of the photo, I have problems. Let’s say it is a photo of me with some friends, and I erase my face, where there are now only white, blank pixels where my face use to be.

If I now print the job, I still get the two calls to DrvStretchBlt, I still collect the size info on first pass, and on second pass I punt to EngStretchBlt which returns success. But the resulting image is wrong. It ends up dropping most of the content, with only a small area coming through, for example, a portion of the lower right corner of the bitmap will come through correct, and in the correct location, but the rest of the bitmap will be blank, as if it wasn’t drawn on.

I suspect that it has something to do with the adjusted coordinates to the destination SURFOBJ, but in both cases I am using the exact same coordinates, etc, and the call being punted to EngStretchBlt. I cannot figure out why EngStretchBlt is exhibiting different behavior for these two cases.

Anyone familiar with this kind of issue?

Thanks for any help,
Cary

xxxxx@hotmail.com wrote:

If I keep this same job in CorelDraw, but grab the CorelDraw erase tool, and erase a portion of the photo, I have problems. Let’s say it is a photo of me with some friends, and I erase my face, where there are now only white, blank pixels where my face use to be.

If I now print the job, I still get the two calls to DrvStretchBlt, I still collect the size info on first pass, and on second pass I punt to EngStretchBlt which returns success. But the resulting image is wrong. It ends up dropping most of the content, with only a small area coming through, for example, a portion of the lower right corner of the bitmap will come through correct, and in the correct location, but the rest of the bitmap will be blank, as if it wasn’t drawn on.

I suspect that it has something to do with the adjusted coordinates to the destination SURFOBJ, but in both cases I am using the exact same coordinates, etc, and the call being punted to EngStretchBlt. I cannot figure out why EngStretchBlt is exhibiting different behavior for these two cases.

Have you dumped the parameters to EngStretchBlt to make sure they are
exactly the same in both cases? Is your SURFOBJ the same format as the
one you are replacing? Is a raster op being specified? Is there a
clipping region?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Tim,

Thanks for the response. The SURFOBJ is the same format as the one I am replacing, and I have examined the parameters to EngStretchBlt and they are the same both cases.

After wrestling with this all morning I think I figured it out. The problem ended up being that the incoming CLIPOBJ clipped regions which were coordinates for the original SURFOBJ.

In the first case, with the unaltered photo, the incoming CLIPOBJ was a trivial simple RECT, and the punt to EngStretchBlt worked great.

In the second case, with the photo having an erased portion, the incoming CLIPOBJ contained a COMPLEX clipping region, which used rectangles based off of the coordinates for the original SURFOBJ.

I couldn’t think of any way to “correct” the incoming CLIPOBJs entire clipping path before punting to EngStretchBlt, so the solution ended up being to inform the GDI where the top left corner of the new SURFOBJ is located within the original SURFOBJ. This is done by setting the new top left corner in DrvNextBand by adjusting the incoming pptl argument.

Once done, all of the subsequent calls for the page have CLIPOBJS, destination RECTS, etc, which are already correctly aligned for the new SURFOBJ by the GDI, enabling me to punt the complete incoming argument list “as is” to EngStretchBlt.

So far this solution seems to be working fine.

Cary

xxxxx@hotmail.com wrote:

I couldn’t think of any way to “correct” the incoming CLIPOBJs entire clipping path before punting to EngStretchBlt, so the solution ended up being to inform the GDI where the top left corner of the new SURFOBJ is located within the original SURFOBJ. This is done by setting the new top left corner in DrvNextBand by adjusting the incoming pptl argument.

Once done, all of the subsequent calls for the page have CLIPOBJS, destination RECTS, etc, which are already correctly aligned for the new SURFOBJ by the GDI, enabling me to punt the complete incoming argument list “as is” to EngStretchBlt.

Congratulations on finding that solution. That’s good investigative work.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

You could rebase all of the coordinates in the region, but your solution of adjusting the origin is probably more reliable

The important point here is that white != blank. Unfortunately, the input you get here will depend to a great degree on how the application is coded, but assuming it uses reasonably modern GDI / GDI+ calls, the regions will be alpha blended to (depending on the image format) allow windows with lower z order / paper to show through.

Again this depends to a great extent on how the application behaves and what the meaning of ?erase? is, but you should be prepared to handle arbitrary complex regions ? which your solution will do

Sent from Mailhttps: for Windows 10

From: xxxxx@hotmail.commailto:xxxxx
Sent: April 26, 2017 2:35 PM
To: Windows System Software Devs Interest Listmailto:xxxxx
Subject: RE:[ntdev] Strange DrvStretchBlt/EngStretchBlt Behaviour

Tim,

Thanks for the response. The SURFOBJ is the same format as the one I am replacing, and I have examined the parameters to EngStretchBlt and they are the same both cases.

After wrestling with this all morning I think I figured it out. The problem ended up being that the incoming CLIPOBJ clipped regions which were coordinates for the original SURFOBJ.

In the first case, with the unaltered photo, the incoming CLIPOBJ was a trivial simple RECT, and the punt to EngStretchBlt worked great.

In the second case, with the photo having an erased portion, the incoming CLIPOBJ contained a COMPLEX clipping region, which used rectangles based off of the coordinates for the original SURFOBJ.

I couldn’t think of any way to “correct” the incoming CLIPOBJs entire ````````````````````````````````````````````````122222222222Once done, all of the subsequent calls for the page have CLIPOBJS, destination RECTS, etc, which are already correctly aligned for the new SURFOBJ by the GDI, enabling me to punt the complete incoming argument list “as is” to EngStretchBlt.

So far this solution seems to be working fine.

Cary


NTDEV is sponsored by OSR

Visit the list online at: http:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at http:

To unsubscribe, visit the List Server section of OSR Online at http:</http:></http:></http:></mailto:xxxxx></mailto:xxxxx></https:>