Rounding errors when scaling the rendered output of the rich edit control via EM_FORMATRANGE - c++

I am using the EM_FORMATRANGE message to render the output of a rich text control to an arbitrary device context. However, when rendering to a bitmap, the dots-per-inch of the bitmap's device context is the same as the display device's DPI, which is 96 dots-per-inch. This is much lower than what I would like to render to. I'd rather render at a much higher DPI so that the user can zoom in, and perhaps print on a high-DPI printer later.
I suspect what happens is that the RTF control calls GetDeviceCaps with LOGPIXELSX and LOGPIXELSY to get the number of pixels per inch of the device. It then renders the document using this DPI value at a 100% zoom level. Windows display devices always return a value of 96 DPI, unless large fonts are being used on the system (as set in Control Panel) and the application is DPI-aware.
Many examples on the Internet propose scaling the output of EM_FORMATRANGE. This is so that any arbitrary DPI resolution can be achieved. Most examples generally involve using SetMapMode, SetWindowExtEx, and SetViewportExtEx (e.g. see http://social.msdn.microsoft.com/Forums/en-us/netfxbcl/thread/37fd1bfb-f07b-421d-9b5e-5f4492ffbbc3). These functions can be used to scale the rich text control's rendered output: for example, if I specify 400% scaling, then if the rich text control rendered something that was 5 pixels wide, it would actually become 20 pixels wide.
Unfortunately, the old GDI functions use integers instead of floating point numbers. For example, suppose the RTF control decided that an element should be drawn at (12.7, 15.3) pixels. This would be rounded to a position of (13, 15). These rounded coordinates are passed to GDI, which then scales up the image using scaling specified by SetMapMode: for the example of 400%, it would be (13*4, 15*4), or (52, 60). But this is not accurate: the element would have better been placed at (12.7*4, 15.3*4), or (51, 61). The worst part is that for some cases, the error becomes cumulative.
I believe this is the underlying cause of this very noticeable error when scaling some simple text:
The above example is 8 point Segoe UI, scaled to 400% using EM_FORMATRANGE and SetMapMode on a 96 DPI display device context. The text has now become 32 point size, but the space between each character is too high and looks unnatural.
The above example was created in WordPad by entering the text as 8 point Segoe UI and then using the zoom control to set to a 400% zoom level. The space between each character looks normal. The exact same result is achieved with a 32 point font and 100% zoom level.
To work around this issue, I have tried the following. For each thing tried, the result has been identically unsatisfactory when scaled to 400%.
Using a scaling transform set using SetWorldTransform instead of the scaling done with SetMapMode and SetWindowExtEx etc.
Passing the device context for a metafile to EM_FORMATRANGE, and then scaling the metafile later.
Using SetMapMode to scale in conjunction with rendering to a metafile, and then showing the metafile later without scaling.
I believe the results are always unsatisfactory because the problem boils down to the fact that the rich edit control is rounding to the nearest integer and rendering to what it thinks is a 96 DPI device - ignoring the transforms in place. I looked into the metafile format and what I discovered is that the individual character positions are actually stored in the metafile at pixel-level resolution - that's why scaling the metafile obviously didn't work since the rounding has already happened by that point.
I can think of two real solutions that would work around this issue:
Use a device context with a higher user-specified dots per inch, such that GetDeviceCaps returns different values. (Note: some examples propose using the printer device since they generally have higher DPI, but I want my code to work on systems that don't have a printer and be able to render to an off-screen buffer).
Some way to tell the rich edit control to assume the device context has a different dots per inch than reported by GetDeviceCaps.
Anything else seems like it would still be subject to these rounding errors.
Does anyone (1) have an idea of how to implement either of the solutions I have proposed, or (2) have an alternate idea of how to achieve my goal of getting an accurate high-DPI output into a buffer?

I'm having the exact same problem.
A quick solution is to draw the text into 100% scale bitmap, and then just scale the bitmap.
it's not the best solution, but it might work for you.
Did you find any better solutions? if so, please share them here.
Also notice, that this problem also occurs when you draw the text to a 100% meta-file and then scale the meta-file to the screen - I believe this has something to do with GDI text drawing functions that aren't working well with scaling.
Roey

You could multiply the point size of all the text in the control by a factor of 4 and render the control to a bitmap that's 4 times larger.
If you're populating the control yourself this would be quite straightforward. If you support arbitrary content entered by the user it would be a lot more work and would require extra effort to handle anything that wasn't text (e.g. embedded bitmaps).

I just spent two weeks on a similar problem. I needed a Rich Edit that was scalable for WYSISWG editing. As we've found the windows rich edit control does not support scaling correctly with EM_FORMATRANGE and inter character spacing does not change between zoom levels and font sizes only scale in discrete font size steps.
Since I did not need large differences in scale the solution I settled on was to use the windowless text edit interfaces from ITextServices to render to an internal bitmap at a fixed resolution. Then I used GDI+ to resample the internal bitmap to the needed screen size with trilinear filtering. The results emulated a scalable rich edit well enough as long as scale difference were not too large, it was good enough for my needs.
After trying many different options I am convinced you can not get precise scaling with the windows rich edit control. You can write your own control that renders text. However, you would need to have a separate draw call for every piece of text with a different style. Also you would need to handle all the nicities rich edit handles for you like highlighting text, placing the cursor, handling mouse and keyboard input, parsing rtf text, et cetera. It would probably be best just to buy a third party component in this case(I could not find any suitable free open source components). In case someone wants to attempt it I will point out the relevant starting points for text rendering for different APIs.
GDI - TextOut does not set inter-character spacing correctly. You need GetCharacterPlacement and ExTextOut. You also need to calculate scaling yourself. You probably don't want to use GDI
GDI+ - DrawString handles scaling correctly. GDI+ is a reasonable option
DirectWrite - If you are willing to limit yourself to Vista Platform Update or later, DirectWrite is the newest text API from Microsoft.
Also here is link describing how text rendering is different between GDI and GDI+:
http://windowsclient.net/articles/gdiptext.aspx

Try using the EM_SETZOOM message to let the rich edit control scale the output itself.

Related

Dealing with DPI and ID2D1RenderTarget::DrawBitmap

I created this UI framework in Direct2D some time ago to be able to draw/manage my own windows and widgets. I've been using it and updating it according to my needs and it works pretty well. However, now that high resolutions monitors are the new thing, I came across a small problem. Drawing images/icons in the best definition I can.
Since I'm using Direct2D all the draw functions work properly according to the DPIs/scaling of the target machines except of course images that are based in pixels and for that reason are not automatically managed by DirectX.
So, in the beginning I was simply drawing bitmaps as they were in 96 DPI, this meant that if I had an icon 10x10, and I used a function like ID2D1RenderTarget::DrawBitmap by specifying a destination rectangle, my image would be scaled up for higher DPIs. This of course would be noticeable and the icon would be blurry.
My first attempt at fixing this was to create my icons 4x bigger than the default DPI of 96. Then, using the same ID2D1RenderTarget::DrawBitmap and knowing that these images are 4x bigger, the DrawBitmap would draw the icon scaled down instead of scaled up. This had much better results, Starting from a windows scale of 150% and up it's perfect.
However, scaling down from 4x to 1x, the result is not great, images get somewhat pixelized. Much worse that doing the same in Photoshop.
I also tried using SetTransform before the DrawBitmap so see if the result is better, but it's exactly the same.
So my question is, how are people dealing with this issue. I'm sure I'm not the only one...
If your goal is to get best visual results, you'll need to prepare groups of icons in various resolutions, not just downscaled but specifically designed in lower sizes. Then you'll need to select one of those according to current context.
Regarding DrawBitmap, you could try with different interpolation modes.
As for general solutions that people are using, I don't think there is one. Many applications don't support this properly, or if they do for control layout, embedded bitmap resources are still stretched and look deformed or interpolated and look too blurry.

How to use accurate GDI font size?

A generic question: in GDI, the type of font size is int, so it is not accurate when do zoom out/ zoom in for the text draw by GDI in the window,
Is there a simple method to use a float font size in GDI to make font size accurate?
Thanks a lot for your kindly help!
GDI text does not scale linearly, and not just because it uses only integer sizes, but also because of hinting which tries to make text look better when rendered at a resolution on the order of its stroke width. If you double the height of a GDI font, the width may not exactly double. GDI text was once hardware accelerated but no longer is on modern versions of Windows. That doesn't matter much for performance because it's relatively simple and efficient, and hardware is fast.
GDI+ text will scale linearly in the sense that doubling the height will double the width (well, it's really close). But text may look "fuzzier" because it uses grayscale antialiasing instead of ClearType subpixel rendering. GDI+ text tends to be slower that GDI because more work is done in software.
DirectWrite (which runs on Direct2D) scales linearly and generally looks very good. It's harder to write efficient Direct2D/DirectWrite code, and, depending on your requirements, you might have to drop back to GDI if you also need to print. If you try to write DPI-aware programs, you may find yourself having to do a lot of conversions between DirectWrite's device-independent coordinates for graphics and mouse coordinates that are still device-dependant. DirectWrite is hardware accelerated, so i'ts fast if you use it efficiently by caching lots of intermediate data structures.
With CreateFont (and CreateFontIndirect) you specify the font size in pixels, so it remains accurate to the pixel regardless of zooming (within the constraints of the sizes available in the font that's selected--if you use a bitmapped font, scaling may be limited or nonexistent).
If you're using CreatePointFont to create the font, you specify the font size in tenths of a point, which usually works out to smaller than a pixel, so it gets rounded to the nearest pixel. If you really want to be sure you're specifying the height to the nearest pixel, however, you probably want to use CreateFont/CreateFontIndirect instead of CreatePointFont though.

scaling a bitmap without losing quality

i have a little problem .. i am developing an SkinEngine that allow Delphi Vcl Application to be Skined . for this goal, i had developed a new file format (mSkin) in order to host my skin data .so my skin file contains 2 header , the first contains some information about the colors used by the skin , the second contains the bitmap used by skin (the bitmap type is Alpha channel bitmap in order to support transparency ).in my control i use a function to extract object bitmap from the bitmap(mSkin.Bitmap) and draw this bitmap onto my control . the problem is that when the bitmap is not shaped i got a bad quality when scaling the source bitmap .the size of the object bitmap is proportional to the control size (when the contol size changed ==> the bitmap siwe change too .)
i had try to read the vcl style to solve the problem .. but it seems to be very difficult to read .
is there a way to copy bitmap and Maintaining the quality ?
If you use bitmaps you simple can't do scaling without the problems you have. If you want scaling where e.g. a one-pixel border stays a one-pixel border, then you have to use a vector-based format for your images.
You need to divide that into 9 different bitmaps, like a 3x3 grid. then you only scale the middle on, the rest stay the same size but move. This link is for android but the same principles apply.
Here is another link. This is for flash, but it also explains the principle.
Try to use a resampling algorithm.
For upscaling, I like very much the B-Spline.
For simple content like yours, the hqnx family sometimes gives good results, and is very fast to render (even in real-time). For some pascal source code, you may take a look at this forum thread.
See also this more general question.

Controlling the individual pixels of a projector

I need to control the individual pixels of a projector (an Infocus IN3104) whose native resolution is 1024x768. I would like to know which subset of functions in C or an APL to do this either by:
Functions that control the individual pixels of the adapter (not the pixels of a window).
A pixel-perfect, 1:1 map from an image file (1024x728) to the adaptor set at the native resolution of the projector.
In a related question ([How can I edit individual pixels in a window?][1]) the answerer Caladain states "Things have come a bit from the old days of direct memory manipulation.". I feel I need to go back to that to achieve my goal.
I don't know enough of the "graphic pipeline" to know what API or software tool to use. I'm overwhelmed by the number of technologies when I search this topic. I program in R, which easily interfaces to C, but would welcome suggestions of subsets of functions in OpenGL or C++ or ..... any other technology?
Or even an full blown application (rendering) which will map without applying a transformation.
For example even MS paint has the >VIEW>Bitmap but I get some transformation applied and I don't get pixel perfect rendering. This projector has DisplayLink digital input and I've also tried to tweek the timing parameters when using the VESA inputs and I don't think the transformation happens in the projector. In any case, using MS paint would not be flexible enough for me.
Platform: Linux or Windows.
I don't see a reason why a full-screen window, e.g. using SDL, wouldn't work. Normal bitmapped graphics is always 1:1, there shouldn't be any weird scaling going on behind your back for a full-screen:ed window.
Since SDL is portable, you should be able to run the same code in Windows or Linux (or any other supported platform).
The usual approach to this problem on current systems is:
Set graphics card to desired resolution
Create borderless full screen window
Draw whatever you want
There's really not much to gain from a "low level access", although it were certainly possible.

Rendering formatted text in a direct3d application

I need to render some formatted text (colours, different font sizes, underlines, bold, etc) however I'm not sure how to go about doing it. D3DXFont only allows text of a single font/size/weight/colour/etc to be rendered at once, and I cant see a practical way to "combine" multiple calls to ID3DXFont::DrawText to do such things...
I looked around and there doesn't seem to be any existing libraries that do these things, but I have no idea how to implement such a text renderer, and I couldn't even find any documentation on how such a text render would work, only rendering simple fixed width, ASCII bitmap fonts which looking at it is probably an entirely different approach that is only suitable for rendering simple blocks of text where Unicode is not important.
If there's no direct3d font renders capable of doing this, is there any other renderers (eg for use in rendering rich text in a normal window), and would rendering those to a texture in RAM, then uploading that to the video card to render onto the back buffer yield reasonable performance?
You tagged this with Direct3D, so I'm going to assume that's the target environment. Otherwise, GDI can handle all this stuff.
Actually, looking at GDI is a good place to start, since it supports this as it stands. With GDI, there is only a single font selected at a time for drawing text. Similarly, there can only be a single text color selected at a time. So, to draw a line of text that contains characters in multiple colors and/or fonts, you have to divide the line up into chunks of characters that all have the same rendering state. You set the state for that chunk (text foreground/background color, text font, text spacing, etc.), then call ::TextOut for that chunk of text, then set the state for the next chunk and draw that, and so-on.
The same principle applied in Direct3D. Each chunk of text may require its own ID3DXFont (or your own font mechanism if ID3DXFont isn't sufficient) and color, etc. You set state, draw text, set state, draw text, etc.
Now, if you want to do your own text rendering, you could do fancier things with a shader, but its probably not worth it unless you have the need for really high-quality typography.
In Windows 7 (back-filled for Vista once Windows 7 ships), you'll be able to use DirectWrite for high quality typography in a Direct3D rendering context (D3D10 and later).
In case of using Direct3D9 or early you really have big problems:
1. You always may use GDI, render your text in the HDC, copy it to the Direct3D dynamic texture and use shader to replace background to transparency by color key for example.
2. Take a look on FreeType library may be you'll find it more suitable for you than GDI, but it really will not be easy.
Any way even if you will find a good way of text rendering you obligotary will have problems with small fonts by reason of ClearType Microsoft technology. At first you will not be able just make a matrix of small symbols to type text from it (because symbol is rendered with using of this subpixel rendering). You will probably need some special shader... or you will be enforced reject to use ClearType, but as i've said before it has bad aftereffects on small fonts. At second this technology is patented by Microsoft
But if you do not need support of Windows XP you may try to use Direct2D with DirectWrite and DirectX10 (I didn't try 11). I tried them and they shown good results, you only should avoid often switching between Direct2D and Direct3D contexts, because it may seriously degrade performance. To render something to your texture you may use ID2D1Factory::CreateDxgiSurfaceRenderTarget function
I suggest measuring the performance of rendering to a bitmap and uploading to a texture.
I suspect that this pretty much what D3DXFont has to do behing the scenes anyway.
You could probably cache letters / phrases etc. if needed