I am trying to set up rust imgui for a custom renderer I am porting to rust.
I am stuck on two fronts, getting the peripheral callbacks, and the rendering.
In C++ the setup was farily simple
ImGuiContext* InitImgui(ModuleStorage::ModuleStorage& module, NECore::Gallery& gallery)
{
ImGuiContext* imgui_context = ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
CpuImage font_image(pixels, width, height, 4);
uint font_id = gallery.StoreImage<CpuImage::GetImageData>(
font_image, "__ImguiFont", NECore::ImageFormat::R8G8B8A8_UNORM);
io.Fonts->SetTexID((ImTextureID)(intptr_t)font_id);
ImGui_ImplGlfw_InitForVulkan(module.GetWindow().GetGLFWWindow(), true);
imgui_shader = module.AddShader(
{"./CommonShaders/imgui.vert",
"./CommonShaders/imgui.frag"});
return imgui_context;
}
30 lines of code and we have the initialization done.
Well some issues in rust, io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); does not exist. I assume the equivalent is let font = fonts.build_rgba32_texture();
Assuming that's the case the next issue is setting the texture id, which I cannot find anywhere in the docs or the source code.
io.Fonts->SetTexID((ImTextureID)(intptr_t)font_id);
That function does not exist in the rust bindings. And ImGui_ImplGlfw_InitForVulkan is no where to be found either.
The examples https://github.com/imgui-rs/imgui-rs/blob/main/imgui-examples/examples/support/mod.rs
Seem to be using pre existen renderers and do not do a good job of showing how to integrate the tool onto an existing renderer other than the ones the author chose, which is baffling, one of the biggest selling points of imgui is how simple it is to integrate in pre-existing codebases.
I am at a loss, hwo do you bootstrap the library in rust?
Related
I'm an experienced programmer specialized in Computer Graphics, mainly using Direct3D 9.0c, OpenGL and general algorithms. Currently, I am evaluating Direct2D as rendering technology for a professional application dealing with medical image data. As for rendering, it is a x64 desktop application in windowed mode (not fullscreen).
Already with my very initial steps I struggle with a task I thought would be a no-brainer: Rendering a single-channel bitmap on screen.
Running on a Windows 8.1 machine, I create an ID2D1DeviceContext with a Direct3D swap chain buffer surface as render target. The swap chain is created from a HWND and buffer format DXGI_FORMAT_B8G8R8A8_UNORM. Note: See also the code snippets at the end.
Afterwards, I create a bitmap with pixel format DXGI_FORMAT_R8_UNORM and alpha mode D2d1_ALPHA_MODE_IGNORE. When calling DrawBitmap(...) on the device context, a debug break point is triggered with the debug message "D2d DEBUG ERROR - This operation is not compatible with the pixel format of the bitmap".
I know that this output is quite clear. Also, when changing the pixel format to DXGI_FORMAT_R8G8B8A8_UNORM with DXGI_ALPHA_MODE_IGNORE everything works well and I see the bitmap rendered. However, I simply cannot believe that! Graphics cards support single-channel textures ever since - every 3D graphics application can use them without thinking twice. This goes without speaking.
I tried to find anything here and at Google, without success. The only hint I could find was the MSDN Direct2D page with the (supported pixel formats). The documentation suggests - by not mentioning it - that DXGI_FORMAT_R8_UNORM is indeed not supported as bitmap format. I also find posts talking about alpha masks (using DXGI_FORMAT_A8_UNORM), but that's not what I'm after.
What am I missing that I can't convince Direct2D to create and draw a grayscale bitmap? Or is it really true that Direct2D doesn't support drawing of R8 or R16 bitmaps??
Any help is really appreciated as I don't know how to solve this. If I can't get this trivial basics to work, I think I'd have to stop digging deeper into Direct2D :-(.
And here is the code snippets of relevance. Please note that they might not compile since I ported this on the fly from my C++/CLI code to plain C++. Also, I threw away all error checking and other noise:
Device, Device Context and Swap Chain Creation (D3D and Direct2D):
// Direct2D factory creation
D2D1_FACTORY_OPTIONS options = {};
options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
ID2D1Factory1* d2dFactory;
D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, options, &d2dFactory);
// Direct3D device creation
const auto type = D3D_DRIVER_TYPE_HARDWARE;
const auto flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
ID3D11Device* d3dDevice;
D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0, D3D11_SDK_VERSION, &d3dDevice, nullptr, nullptr);
// Direct2D device creation
IDXGIDevice* dxgiDevice;
d3dDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice));
ID2D1Device* d2dDevice;
d2dFactory->CreateDevice(dxgiDevice, &d2dDevice);
// Swap chain creation
DXGI_SWAP_CHAIN_DESC1 desc = {};
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 2;
IDXGIAdapter* dxgiAdapter;
dxgiDevice->GetAdapter(&dxgiAdapter);
IDXGIFactory2* dxgiFactory;
dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&dxgiFactory));
IDXGISwapChain1* swapChain;
dxgiFactory->CreateSwapChainForHwnd(d3dDevice, hwnd, &swapChainDesc, nullptr, nullptr, &swapChain);
// Direct2D device context creation
const auto options = D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
ID2D1DeviceContext* deviceContext;
d2dDevice->CreateDeviceContext(options, &deviceContext);
// create render target bitmap from swap chain
IDXGISurface* swapChainSurface;
swapChain->GetBuffer(0, __uuidof(swapChainSurface), reinterpret_cast<void **>(&swapChainSurface));
D2D1_BITMAP_PROPERTIES1 bitmapProperties;
bitmapProperties.dpiX = 0.0f;
bitmapProperties.dpiY = 0.0f;
bitmapProperties.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
bitmapProperties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
bitmapProperties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE;
bitmapProperties.colorContext = nullptr;
ID2D1Bitmap1* swapChainBitmap = nullptr;
deviceContext->CreateBitmapFromDxgiSurface(swapChainSurface, &bitmapProperties, &swapChainBitmap);
// set swap chain bitmap as render target of D2D device context
deviceContext->SetTarget(swapChainBitmap);
D2D single-channel Bitmap Creation:
const D2D1_SIZE_U size = { 512, 512 };
const UINT32 pitch = 512;
D2D1_BITMAP_PROPERTIES1 d2dProperties;
ZeroMemory(&d2dProperties, sizeof(D2D1_BITMAP_PROPERTIES1));
d2dProperties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE;
d2dProperties.pixelFormat.format = DXGI_FORMAT_R8_UNORM;
char* sourceData = new char[512*512];
ID2D1Bitmap1* d2dBitmap;
deviceContext->DeviceContextPointer->CreateBitmap(size, sourceData, pitch, d2dProperties, &d2dBitmap);
Bitmap drawing (FAILING):
deviceContext->BeginDraw();
D2D1_COLOR_F d2dColor = {};
deviceContext->Clear(d2dColor);
// THIS LINE FAILS WITH THE DEBUG BREAKPOINT IF SINGLE CHANNELED
deviceContext->DrawBitmap(bitmap, nullptr, 1.0f, D2D1_INTERPOLATION_MODE_LINEAR, nullptr);
swapChain->Present(1, 0);
deviceContext->EndDraw();
From my little experience, Direct2D seems very limited, indeed.
Have you tried Direct2D effects (ID2D1Effect)? You can write your own [it seems comparatively complicated], or use one of the built-in effects [which is rather simple].
There is one called Color matrix effect (CLSID_D2D1ColorMatrix). It might work to have your DXGI_FORMAT_R8_UNORM (or DXGI_FORMAT_A8_UNORM, any single-channel would do) as input (inputs to effects are ID2D1Image, and ID2D1Bitmap inherits from ID2D1Image). Then set the D2D1_COLORMATRIX_PROP_COLOR_MATRIX for copying the input channel to all output channels. Have not tried it, though.
I have a Windows application which I want to look good at high DPI monitors. The application is using DEFAULT_GUI_FONT in lots of places, and the font created this way doesn't scale correctly.
Is there any simple way to fix this problem with not too much pain?
you need get NONCLIENTMETRICS by SystemParametersInfo(SPI_GETNONCLIENTMETRICS,) and then use it LOGFONT data, for create self font. or you can query for SystemParametersInfo(SPI_GETICONTITLELOGFONT) and use it
The recommended fonts for different purposes can be obtained from the NONCLIENTMETRICS structure.
For automatically DPI-scaled fonts (Windows 10 1607+, must be per-monitor DPI-aware):
// Your window's handle
HWND window;
// Get the DPI for which your window should scale to
UINT dpi = GetDpiForWindow(window);
// Obtain the recommended fonts, which are already correctly scaled for the current DPI
NONCLIENTMETRICSW non_client_metrics;
if (!SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, sizeof(non_client_metrics), &non_client_metrics, 0, dpi)
{
// Error handling
}
// Create an appropriate font(s)
HFONT message_font = CreateFontIndirectW(&non_client_metrics.lfMessageFont);
if (!message_font)
{
// Error handling
}
For older Windows versions you can use the system-wide DPI and scale the font manually (Windows 7+, must be system DPI-aware):
// Your window's handle
HWND window;
// Obtain the recommended fonts, which are already correctly scaled for the current DPI
NONCLIENTMETRICSW non_client_metrics;
if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(non_client_metrics), &non_client_metrics, 0)
{
// Error handling
}
// Get the system-wide DPI
HDC hdc = GetDC(nullptr);
if (!hdc)
{
// Error handling
}
UINT dpi = GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(nullptr, hdc);
// Scale the font(s)
constexpr UINT font_size = 12;
non_client_metrics.lfMessageFont.lfHeight = -((font_size * dpi) / 72);
// Create the appropriate font(s)
HFONT message_font = CreateFontIndirectW(&non_client_metrics.lfMessageFont);
if (!message_font)
{
// Error handling
}
NONCLIENTMETRICS has also many other fonts in it. Make sure to choose the right one for your purpose.
You should set the DPI-awareness level in your application manifest as described here for best compatibility.
WinForms in the .NET framework internally converts the DEFAULT_GUI_FONT (which is in fact used to get the default font for WinForms Forms and Controls in most situations) by scaling its height from pixels (which is the unit GDI fonts use natively) to Points (which is preferred by GDI+). Drawing text using points implies that the physical size of the rendered text depends on the monitor DPI setting.
System.Drawing.Font.SizeInPoints:
float emHeightInPoints;
IntPtr screenDC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef);
try {
using( Graphics graphics = Graphics.FromHdcInternal(screenDC)){
float pixelsPerPoint = (float) (graphics.DpiY / 72.0);
float lineSpacingInPixels = this.GetHeight(graphics);
float emHeightInPixels = lineSpacingInPixels * FontFamily.GetEmHeight(Style) / FontFamily.GetLineSpacing(Style);
emHeightInPoints = emHeightInPixels / pixelsPerPoint;
}
}
finally {
UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, screenDC));
}
return emHeightInPoints;
Obviously you cannot use this directly as it's C#. But besides that, this article suggests that you should scale pixel dimensions assuming a 96 dpi design, and use GetDpiForWindow to determine the actual DPI. Note that the "72" in the formula above has nothing to do with the monitor DPI setting, it comes from the fact that .NET likes to use fonts specified in points rather than pixels (otherwise just scale the LOGFONT's height by DPIy/96).
This site suggests something similar, but with GetDpiForMonitor.
I cannot say for sure whether the general approach of manually scaling the font size according to some DPI-dependent factor is a robust and future-proof for scaling fonts (it seems to be the way to go about scaling non-font GUI elements though). However, since .NET basically also just calculates some magic factor based on some sort of DPI value, it's probably a pretty good guess.
Also, you'll want to cache that HFONT. HFONT - LOGFONT conversions are not negligible.
See also (references):
WinForms gets its default using GetStockObject(DEFAULT_GUI_FONT) (there are a few exceptions though, mostly obsolete):
IntPtr handle = UnsafeNativeMethods.GetStockObject(NativeMethods.DEFAULT_GUI_FONT);
try {
Font fontInWorldUnits = null;
// SECREVIEW : We know that we got the handle from the stock object,
// : so this is always safe.
//
IntSecurity.ObjectFromWin32Handle.Assert();
try {
fontInWorldUnits = Font.FromHfont(handle);
}
finally {
CodeAccessPermission.RevertAssert();
}
try{
defaultFont = FontInPoints(fontInWorldUnits);
}
finally{
fontInWorldUnits.Dispose();
}
}
catch (ArgumentException) {
}
https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/SystemFonts.cs,355
The HFONT is converted to GDI+, and then the GDI+ font retrieved this way is transformed using FontInPoints:
private static Font FontInPoints(Font font) {
return new Font(font.FontFamily, font.SizeInPoints, font.Style, GraphicsUnit.Point, font.GdiCharSet, font.GdiVerticalFont);
}
https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/SystemFonts.cs,452
The content of the SizeInPoints getter is already listed above.
https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Advanced/Font.cs,992
I'm altering someone else's code. They used PNG's which are loaded via BufferedImage. I need to load a TGA instead, which is just simply a 18 byte header and BGR codes. I have the textures loaded and running, but I get a gray box instead of the texture. I don't even know how to DEBUG this.
Textures are loaded in a ByteBuffer:
final static int datasize = (WIDTH*HEIGHT*3) *2; // Double buffer size for OpenGL // not +18 no header
static ByteBuffer buffer = ByteBuffer.allocateDirect(datasize);
FileInputStream fin = new FileInputStream("/Volumes/RAMDisk/shot00021.tga");
FileChannel inc = fin.getChannel();
inc.position(18); // skip header
buffer.clear(); // prepare for read
int ret = inc.read(buffer);
fin.close();
I've followed this: [how-to-manage-memory-with-texture-in-opengl][1] ... because I am updating the texture once per frame, like video.
Called once:
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, width, height, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null);
assert(GL11.GL_NO_ERROR == GL11.glGetError());
Called repeatedly:
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, width, height, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, byteBuffer);
assert(GL11.GL_NO_ERROR == GL11.glGetError());
return textureID;
The render code hasn't changed and is based on:
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, this.vertexCount);
Make sure you set the texture sampling mode. Especially min filter: glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR). The default setting is mip mapped (GL_NEAREST_MIPMAP_LINEAR) so unless you upload mip maps you will get a white read result.
So either set the texture to no mip or generate them. One way to do that is to call glGenerateMipmap after the tex img call.
(see https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexParameter.xml).
It's a very common gl pitfall and something people just tend to know after getting bitten by it a few times.
There is no easy way to debug stuff like this. There are good gl debugging tools in for example xcode but they will not tell you about this case.
Debugging GPU code is always a hassle. I would bet my money on a big industry progress in this area as more companies discover the power of GPU. Until then; I'll share my two best GPU debugging friends:
1) Define a function to print OGL errors:
int printOglError(const char *file, int line)
{
/* Returns 1 if an OpenGL error occurred, 0 otherwise. */
GLenum glErr;
int retCode = 0;
glErr = glGetError();
while (glErr != GL_NO_ERROR) {
printf("glError in file %s # line %d: %s\n", file, line, gluErrorString(glErr));
retCode = 1;
glErr = glGetError();
}
return retCode;
}
#define printOpenGLError() printOglError(__FILE__, __LINE__)
And call it after your render draw calls (possible earlier errors will also show up):
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, this.vertexCount);
printOpenGLError();
This alerts if you make some invalid operations (which might just be your case) but you usually have to find where the error occurs by trial and error.
2) Check out gDEBugger, free software with tons of GPU memory information.
[Edit]:
I would also recommend using the opensource lib DevIL - its quite competent in loading various image formats.
Thanks to Felix, by not calling glTexSubImage2D (leaving the memory valid, but uninitialized) I noticed a remnant pattern left by the default memory. This indicated that the texture is being displayed, but the load is most likely the problem.
**UPDATE:
The, problem with the code above is essentially the buffer. The buffer is 1024*1024, but it is only partially filled in by the read, leaving the limit marker of the ByteBuffer at 2359296(1024*768*3) instead of 3145728(1024*1024*3). This gives the error:
Number of remaining buffer elements is must be ... at least ...
I thought that OpenGL needed space to return data, so I doubled the size of the buffer.
The buffer size is doubled to compensate for the error.
final static int datasize = (WIDTH*HEIGHT*3) *2; // Double buffer size for OpenGL // not +18 no header
This is wrong, what is needed is the flip() function (Big THANKS to Reto Koradi for the small hint to the buffer rewind) to put the ByteBuffer in read mode. Since the buffer is only semi-full, the OpenGL buffer check gives an error. The correct thing to do is not double the buffer size; use buffer.position(buffer.capacity()) to fill the buffer before doing a flip().
final static int datasize = (WIDTH*HEIGHT*3); // not +18 no header
buffer.clear(); // prepare for read
int ret = inc.read(buffer);
fin.close();
buffer.position(buffer.capacity()); // make sure buffer is completely FILLED!
buffer.flip(); // flip buffer to read mode
To figure this out, it is helpful to hardcode the memory of the buffer to make sure the OpenGL calls are working, isolating the load problem. Then when the OpenGL calls are correct, concentrate on the loading of the buffer. As suggested by Felix K, it is good to make sure one texture has been drawn correctly before calling glTexSubImage2D repeatedly.
Some ideas which might cause the issue:
Your texture is disposed somewhere. I don't know the whole code but I guess somewhere there is a glDeleteTextures and this could cause some issues if called at the wrong time.
Are the texture width and height powers of two? If not this might be an issue depending on your hardware. Old hardware sometimes won't support non-power of two images.
The texture parameters changed between the draw calls at some other point ( Make a debug check of the parameters with glGetTexParameter ).
There could be a loading issue when loading the next image ( edit: or even the first image ). Check if the first image is displayed without loading the next images. If so it must be one of the cases above.
Pango syntax supports some text only markup. As far as i can see this does not extend to embedding images as well.
Looking around I cannot find much in the way of an existing implementation, but i havent done pango+cairo work before so i might be missing the obvious community for it.
As far as i can tell a reasonable approach would be to just analyse a string, pull out any tags, create cairo images, and then modify the pango layout around them accordingly.
It also seems like something someone might have done before.
Im specifically looking for an answer on these questions:
Does pango+cairo already solve this and I have just misread the docs?
Has something like this been done before, and where is a reference?
Is this a reasonable approach, or should i try something else, and what?
(also note i am using ruby, so that may affect my options)
I've been through the source of the markup parser and it does not allow for "shape" attributes (the way Pango almost incorporates graphics) but it is possible to do it "by hand".
Since there is absolutely no example code on the Web, here's Pango/Cairo/Images 101.
For a simple demo, I created an 800x400 window, added a GtkDrawingArea and connected up the "draw" signal. Before entering the main program loop, I initialized it with the following code:
PangoLayout *Pango;
void init_drawingArea (GtkWidget *pWidget)
{
cairo_surface_t *pImg = cairo_image_surface_create_from_png ("linux.png");
PangoRectangle r = {0, 0, PANGO_SCALE * cairo_image_surface_get_width (pImg),
PANGO_SCALE * cairo_image_surface_get_height(pImg)};
PangoContext *ctxt = gtk_widget_get_pango_context (pWidget);
PangoAttrList *attList = pango_attr_list_new();
PangoAttribute *attr;
Pango = pango_layout_new (ctxt);
pango_cairo_context_set_shape_renderer (ctxt, render, NULL, NULL);
pango_layout_set_text (Pango, pszLorem, -1);
pango_layout_set_width(Pango, PANGO_SCALE * 800);
attr = pango_attr_shape_new_with_data(&r, &r, pImg, NULL, NULL);
attr->start_index = 0; attr->end_index = 1;
pango_attr_list_insert (attList, attr);
attr = pango_attr_shape_new_with_data(&r, &r, pImg, NULL, NULL);
attr->start_index = 152; attr->end_index = 153;
pango_attr_list_insert (attList, attr);
pango_layout_set_attributes (Pango, attList);
}
The context's shape renderer is set to render () and a PangoLayout is created and initialized. It then creates 2 shape attributes, sets the user data to a cairo surface which we populate from a png file and applies the attributes to characters 0 and 152 of the text.
The "draw" signal processing is straightforward.
gboolean onDraw (GtkWidget *pWidget, cairo_t *cr, gpointer user_data)
{
pango_cairo_show_layout (cr, Pango);
return 1;
}
and the render () PangoCairoShapeRenderFunc function is called as needed:
void render (cairo_t *cr, PangoAttrShape *pShape, gboolean do_path, gpointer data)
{
cairo_surface_t *img = (cairo_surface_t *)pShape->data;
double dx, dy;
cairo_get_current_point(cr, &dx, &dy);
cairo_set_source_surface(cr, img, dx, dy);
cairo_rectangle (cr, dx, dy, pShape->ink_rect.width/PANGO_SCALE,
pShape->ink_rect.height/PANGO_SCALE);
cairo_fill(cr);
}
Taking the current point from cairo, it draws a rectangle and fills it with the image.
And that's pretty much all it does. Images were added as an afterthought and it shows. They are subject to the same rules as any other glyph so they are limited to the equivalent of CSS's display: inline.
I've put the code up at http://immortalsofar.com/PangoDemo/ if anyone wants to play with it. Me, I arrived here trying to get around GtkTextBuffer's limitations. Guess I'll just have to go deeper.
I've printed a few short qr-codes (like "HAEB16653") on a page using this algorythm:
private void CreateQRCodeFile(int size, string filename, string codecontent)
{
QRCodeWriter writer = new QRCodeWriter();
com.google.zxing.common.ByteMatrix matrix;
matrix = writer.encode(codecontent, BarcodeFormat.QR_CODE, size, size, null);
Bitmap img = new Bitmap(size, size);
Color Color = Color.FromArgb(0, 0, 0);
for (int y = 0; y < matrix.Height; ++y)
{
for (int x = 0; x < matrix.Width; ++x)
{
Color pixelColor = img.GetPixel(x, y);
//Find the colour of the dot
if (matrix.get_Renamed(x, y) == -1)
{
img.SetPixel(x, y, Color.White);
}
else
{
img.SetPixel(x, y, Color.Black);
}
}
}
img.Save(filename, ImageFormat.Png);
}
The printed barcodes work very well and fast with the integrated WP7 bing scan&search.
When I try to scan the very same printed qrcodes with Stéphanie Hertrichs sample app, scanning is very slow, most do not scan at all, or will only be recognized when I slowly rotate the camera around.
How do I get my scanning to be as reliable as the integrated barcode recognition? I only need to scan QrCodes, so I disabled all the others, still it does not work most of the time.
Is there maybe some other barcode scanning library which is working better?
The silverlight port in Stéphanie Hertrichs sample app is very old. It seems to me that the project at codeplex isn't maintained anymore since more then 1 year. You should try one of the newer and maintained ports like ZXing.Net
zxing works very well -- just try it on Android. I would not be surprised if it is what powers the Bing search.
The problems are likely in the port. Any non-Java port is at best old and incomplete. I also can't speak to the efficiency of the approach used in the sample you are looking at. For example, is it really binarizing the image from the APIs correctly? Also make sure it is not using TRY_HARDER mode.
There is no objective answer to this question...
My personal opinion is that the ZXing lib that you tried (Stéphanie Hertrichs sample app) is the best you can get. As far as I know it is used on the other plattforms, too (e.g. Android).
As I tested the lib a few months ago, I had the impression it worked very reliable and quick, but it may be that you had other circumstances (lighting, camera, angle, etc...)