It seems that there is a limitation to 16 transparent icons you can use in a CComboBoxEx. I have the following pseudo code:
m_ImageList.Create(16,16,ILC_COLOR32,TF_COUNT,1);
for (int nImage = 0; nImage < TF_COUNT; nImage++)
{
m_ImageList.Add(phIcons[nImage]);
DestroyIcon(phIcons[nImage]);
}
m_cmbAction.SetImageList(&m_ImageList);
The first 16 icons are OK - the following ones all have a black background instead of the transparency. The same code and Image list associated to a CTreeCtrl or a CListCtrl works beautifully. Any ideas?
EDIT: I am using Visual Studio 2013
Author posted his code in a ZIP file:
m_ImageList.Create(16, 16, ILC_COLOR32, TF_COUNT, 1);
for (int nIcon=0; nIcon < TF_COUNT; nIcon++)
{
m_ImageList.Add(m_hIcon);
}
m_ComboBox.SetImageList(&m_ImageList);
COMBOBOXEXITEM cbi;
cbi.mask = CBEIF_IMAGE | CBEIF_INDENT | CBEIF_OVERLAY |
CBEIF_SELECTEDIMAGE | CBEIF_TEXT | CBEIF_LPARAM;
int nItemCount = 0;
for (int nText = 0; nText < TF_COUNT; nText++)
{
CString strItem;
strItem.Format(_T("Item %d"),nText);
cbi.iItem = nItemCount;
cbi.pszText = (LPTSTR)(LPCTSTR)strItem;
cbi.cchTextMax = strItem.GetLength();
cbi.iImage = nText;
cbi.iSelectedImage = nText;
cbi.iOverlay = nText;
cbi.iIndent = 0;
cbi.lParam = nText;
m_ComboBox.InsertItem(&cbi);
nItemCount++;
}
In this code, the error is CBEIF_OVERLAY and cbi.iOverlay = nText. Overlay image is an image drawn transparently over another image (this way, you can combine two icons). In the author's code, that is obviously not the intent.
Finally, image lists allow only up to 15 overlay icons. That explains the magic 16.
Solution 1
If you want to use transparency, you need to create image list with a mask:
m_ImageList.Create(16, 16, ILC_COLOR32 | ILC_MASK, TF_COUNT, 1)
Solution 2
Another (worse) approach is to set the desired background color (after creating the imagelist, but before adding the icons):
m_ImageList.SetBkColor(RGB(0xFF, 0xFF, 0xFF))
The problem about the background color is that you will have to figure which background color to use.
The magic number of 16
I don't think your problem is about CComboBoxEx somehow having problems with the number 16. Instead, I think your icons are a bit different, for example some truly 32-bit, and some in other format. You can test it like that:
m_ImageList.Create(16,16,ILC_COLOR32,TF_COUNT,1);
for (int nImage = 0; nImage < TF_COUNT; nImage++)
{
m_ImageList.Add(phIcons[0]);
}
m_cmbAction.SetImageList(&m_ImageList);
This code adds the same icon multiple times. I bet you won't have any issues with that. Now, you can also try this:
m_ImageList.Create(16,16,ILC_COLOR32,TF_COUNT,1);
for (int nImage = 0; nImage < TF_COUNT; nImage++)
{
m_ImageList.Add(phIcons[16]);
}
m_cmbAction.SetImageList(&m_ImageList);
And you will likely have all icons wrong.
Update 1
I do not have any issues with 16+ transparent icons on my Win8.1, so it's time to suspect that third-party software or your own code is the root of the problem. You need to prepare a minimal example of the code still containing the problem, then try it on another computer. It will be best to try on a virtual machine (you can download prebuilt one here) to reduce all possible risks of whatever software you have installed on many machines at once. If your minimal example still shows the problem on virtual machine, zip it and share with us.
Related
I'm trying to code a program that changes a BMP file and adds some modifications in particular locations. The BMPs I'm trying to modify are monochrome (1 bit per pixel) as the image size needs to be quite small. I'm using the ATL CImage class to do this.
However, I can't seem to use SetPixel to change a particular pixel for monochrome BMPs.
(I've modified this code a bit for simplicity. 'color' comes from another part of the program and only ever returns RGB(255,255,255) or RGB(0,0,0))
CImage bmp;
bmp.Create(180, 1369, 1);
for (int y = 0; y < 1369; y++)
{
for (int x = 0; x < 180; x++) {
bmp.SetPixel(x, y, color);
}
}
This code returns a black BMP when displayed. If I modify the '1' in bmp.Create, which is the number of bits per pixel, to anything larger than 8, the code works as expected. However, that fix does not suit me as I end up with a BMP that is too large.
Is there any way of making SetPixel work here?
It appears that when you use Create() to make a monochrome bitmap that it creates one where both colors are black. You'll need to adjust the color table:
RGBQUAD colors[2] = { 0 };
bmp.GetColorTable(0, 2, colors);
colors[1].rgbRed = colors[1].rgbGreen = colors[1].rgbBlue = 0xff;
bmp.SetColorTable(0, 2, colors);
Then if you SetPixel to RGB(0xff,0xff,0xff) it should work properly
Abstract
My ultimate goal is to use Fltk to take user inputs of pixels, display a generated maze (either my own, or fetch it from the website mentioned in the details), and then show the animated solution.
This is what i've managed so far:
https://giant.gfycat.com/VioletWelloffHatchetfish.webm
Details
I'm in my first c++/algorithm class of a bachelors in CE.
As we've been learning about graphs, dijkstra etc. the last weeks i decided after watching Computerphile's video about Maze solving, to try to put the theory into "practice".
At first i wanted to output a maze from this site, http://hereandabove.com/maze/mazeorig.form.html, with the plotted solution. I chose that walls and paths should be 1x1 pixel, to make it easier to make into a 2D-vector, and then a graph.
This went well, and my program outputs a solved .png file, using dijkstra to find the shortest path.
I then wanted to put the entire solution in an animated gif.
This also works well. For each pixel it colors green/yellow, it passes an RGBA-vector to a gif-library, and in the end i end up with an animated step by step solution.
I also for each RGBA-vector passed to the gif-library, scale it up first, using this function:
//Both the buffer and resized buffer are member variables, and for each //plotted pixel in the path it updates 'buffer', and in this function makes a //larger version of it to 'resized_buffer'
// HEIGHT and WIDTH are the original size
// nHeight and nWidth are the new size.
bool Maze_IMG::resample(int nWidth, int nHeight)
{
if (buffer.size() == 0) return false;
resized_buffer.clear();
for (int i = 0; i < nWidth * nHeight * 4; i++) resized_buffer.push_back(-1);
double scaleWidth = (double)nWidth / (double)WIDTH;
double scaleHeight = (double)nHeight / (double)HEIGHT;
for (int cy = 0; cy < nHeight; cy++)
{
for (int cx = 0; cx < nWidth; cx++)
{
int pixel = (cy * (nWidth * 4)) + (cx * 4);
int nearestMatch = (((int)(cy / scaleHeight) * (WIDTH * 4)) + ((int)(cx / scaleWidth) * 4));
resized_buffer[pixel] = buffer[nearestMatch];
resized_buffer[pixel + 1] = buffer[nearestMatch + 1];
resized_buffer[pixel + 2] = buffer[nearestMatch + 2];
resized_buffer[pixel + 3] = buffer[nearestMatch + 3];
}
}
return true;
}
Problems
The problem is that it takes a looong time to do this while scaling them up, even with "small" mazes at 50x50 pixels, when trying to scale them to say 300x300. I've spent a lot of time to make code as efficient and fast as possible, but after i added the scaling, stuff that used to take 10 minutes, now takes hours.
In fltk i use the Fl_Anim_Gif-library to display animated gifs, but it wont load the maze gifs that has been scaled up (still troubleshooting this).
My real questions
Is it possible to improve the scaling function, so that it does not take forever? Or is this a totally wrong approach?
Is it a stupid idea to try to display it as a gif in fltk, would it be easier to just draw it directly in fltk, or should i rather try to display the images one after another i fltk?
I'm just familiarizing myself with fltk. Would it be easier now to use something like Qt instead. Would that be more beneficial in the long run as far as learning a GUI-library goes?
I'm mainly doing this for learning, and to start building some sort of portfolio for when i graduate. Is it beneficial at all to make a gui for this, or is this a waste of time?
Any thoughts or input would be greatly appreciated.
Whatever graphics package you use, the performance will be similar. It depends on how you handle the internals. For instance,
If you write it to a buffer and BLT it to the screen, it would be faster than writing to the screen directly.
If you only BLT on the paint event, it would be faster than forcing and update every time the screen data changes.
If you preallocate the buffers then the system does not have to keep on reallocating whenever the buffer space runs out.
Assuming that the space is preallocated, it can be written to without clearing first. Every cell it going to be written to so no need to clear, allocate and and reallocate.
I'm using the UI Automation C++ library to get text data from another GUI application.
If the GUI application is developed using a framework that support UI Automation (WinForm, WPF, ...), it is very easy to get the text.
This is an example using the Inspect tool of UI Automation SDK:
Here, test with CCleaner Free application, it can get the text "Microsoft Edge"
We can also using Win32 API to send some message (Send Message) to get text, example: WM_GETTEXT, LVM_GETITEMTEXT, ...
But, I can't get the text from following element:
The whole header area is just an element only, and I can't get the text inside it.
First, I think it is just an image, but it is not. This is the result of using Ranorex Spy:
The plugin that Ranorex using to get text is GDI RawText Plug-In:
For some older technologies like VB6.0, Delphi or MFC based
applications, Ranorex has only limited support in addressing UI
elements in a robust way. With the GDI RawText Plug-In Ranorex
increases object recognition for controls which use the Windows GDI
drawing mechanism to display text on screen.
So, is there any tutorial about getting text from Windows GDI drawing in another application? Currently, I can't found any resource about it
PS: First, I think it use some OCR library to recognize text from image, but it get the text very fast, not look like using OCR library.
Ranorex is a commercial tool, so I think they will not let me know what library that they implement the plugin if I ask them
Update 1:
I capture the header bar of CCleaner application to Paint, and use Ranorex Spy to get text from the image (if it use some OCR library):
There is no RawText inside the selected element, so it does not use OCR to get the text
Update 2:
I write some simple MFC application to test:
void CMFCApplication1Dlg::OnPaint()
{
CPaintDC dc(this);
CRect rcText(20, 20, 300, 300);
wchar_t text[36];
wsprintf(text, L"Hello world");
dc.SetBkColor(RGB(255, 255, 255));
dc.DrawText(text, &rcText, DT_LEFT);
CDialogEx::OnPaint();
}
Using Spy++:
Using Inspect:
Using Ranorex Spy:
Update 3
Try set background color to black as well:
void CMFCApplication1Dlg::OnPaint()
{
CPaintDC dc(this);
CRect rcText(20, 20, 300, 300);
wchar_t text[36];
wsprintf(text, L"Hello world");
dc.SetBkColor(RGB(0, 0, 0));
dc.DrawText(text, &rcText, DT_LEFT);
CDialogEx::OnPaint();
}
So, no OCR engine can be used here. But this is the result of using Ranorex Spy:
Here's how you can quickly figure out if Ranorex uses OCR. Take a screenshot of CCleanerFree and paste it to mspaint and then run Ranorex on mspaint window to see if it can read text.
Here's how to detect if Ranorex uses winapi hooks for DrawText to see what text some app is drawing. Create a simple windows app and DrawText manually (preferably draw black text on black background to eliminate OCR possibility). If Ranorex reads it then they use winapi hooks to read your text.
Here's how read text with OCR.
OCR is pretty fast, it doesn't take seconds to process simple screen text. You could take screenshot of that window and process specific area of interest for you. I used ocrad for similar task and it worked out great.
Here's sample code you could try:
#include <stdint.h>
#include <string>
#include "ocradlib.h"
std::string image_to_text(uint8_t *data, int width, int height)
{
OCRAD_Pixmap pixmap = { 0 };
pixmap.data = data;
pixmap.width = width;
pixmap.height = height;
pixmap.mode = OCRAD_greymap; // OCRAD_greymap --> 1 byte per pixel; 256 level greymap
std::string ret;
OCRAD_Descriptor * const ocrdes = OCRAD_open();
if (!ocrdes || OCRAD_get_errno(ocrdes) != OCRAD_ok)
{
OCRAD_close(ocrdes);
fprintf(stderr, "not enough memory.\n");
return ret;
}
if (OCRAD_set_image(ocrdes, &pixmap, false) < 0)
{
const OCRAD_Errno ocr_errno = OCRAD_get_errno(ocrdes);
OCRAD_close(ocrdes);
return ret;
}
if (OCRAD_set_threshold(ocrdes, -1) < 0 || // auto threshold
OCRAD_recognize(ocrdes, false) < 0) // no layout
{
const OCRAD_Errno ocr_errno = OCRAD_get_errno(ocrdes);
OCRAD_close(ocrdes);
return ret;
}
const int blocks = OCRAD_result_blocks(ocrdes);
for (int b = 0; b < blocks; ++b)
{
const int lines = OCRAD_result_lines(ocrdes, b);
for (int l = 0; l < lines; ++l)
{
const char * s = OCRAD_result_line(ocrdes, b, l);
if (s && s[0])
ret += s;
}
if (b + 1 < blocks)
ret += '\n';
}
OCRAD_close(ocrdes);
return ret;
}
note that this code uses grayscale pixmap, e.g. 1 byte per pixel rectangle. You can try to change the code to use other image types:
/* OCRAD_Pixmap.data is a pointer to image data formed by "height" rows
of "width" pixels each.
The format for each pixel depends on mode like this:
OCRAD_bitmap --> 1 byte per pixel; 0 = white, 1 = black
OCRAD_greymap --> 1 byte per pixel; 256 level greymap (0 = black)
OCRAD_colormap --> 3 bytes per pixel; 16777216 colors RGB (0,0,0 = black) */
enum OCRAD_Pixmap_Mode { OCRAD_bitmap, OCRAD_greymap, OCRAD_colormap };
There are also other libraries that may provide better quality for more complex images, but for simple text like that ocrad was perfect for me.
To read text using WinAPI hooks
Read some tutorials to understand how that works. For example Hooks Overview on MSDN.
Here's a tutorial that shows how that can be done using EasyHook: EasyHook - Installing a remote hook using EasyHook with C++. Note that there are multiple functions that draw text in WinAPI, perhaps you'll need to hook one or all of them depending on your needs: DrawText, TextOut, ExtTextOut, ExtTextOutWarp (and others).
Is it possible to create a new tif by iterating pixel by pixel and setting the RGB values for each pixel?
Let me explain what I'm attempting to do. I'm trying to open an existing tif, read it using TIFFReadRGBAImage, take the RGB values given by TIFFGetR/TIFFGetG/TIFFGetB, subtract them from 255, take those new values and use them to write each pixel one by one. In the end I'd like to end up with the original image and a new "complement" image that would be like a negative of the original.
Is there a way to do this using LibTiff? I've gone over the documentation and searched around Google but I've only seen very short examples of TIFFWriteScanline which provide so little lines of code/context/comments that I cannot figure out how to implement it in the way that I'd like it to work.
I'm still fairly new to programming so if someone could please either point me to a thorough example with plenty of explanatory comments or help me out directly with my code, I would appreciate it greatly. Thank you for taking the time to read this and help me learn.
What I have so far:
// Other unrelated code here...
//Invert color values and write to new image file
for (e = height - 1; e != -1; e--)
{
for (c = 0; c < width; c++)
{
red = TIFFGetR(raster[c]);
newRed = 255 - red;
green = TIFFGetG(raster[c]);
newGreen = 255 - green;
blue = TIFFGetB(raster[c]);
newBlue = 255 - blue;
// What to do next? Is this feasible?
}
}
// Other unrelated code here...
Full code if you need it.
I went back and looked at my old code. It turns out that I didn't use libtiff. Nevertheless you are on the right track. You want something like;
lineBuffer = (char *)malloc(width * 3) // 3 bytes per pixel
for all lines
{
ptr = lineBuffer
// modify your line code above so that you make a new line
for all pixels in line
{
*ptr++ = newRed;
*ptr++ = newGreen;
*ptr++ = newBlue
}
// write the line using libtiff scanline write
write a line here
}
Remember to set the tags appropriately. This example assumes 3 byte pixels. TIFF also allows for separate planes of 1 byte per pixel in each plane.
Alternately you can also write the whole image into a new buffer instead of one line at a time.
I need to display some data in table format in a read-only multi-line edit control. Since the the edit control's font doesn't have even width for all texts, I could not use this formatting "%-20s", so I chose to use \t formatting (see code at the below). But that doesn't help me completely because it displays like in the image.
I tried using GetTextExtentPoint32() API but it could not find the exact width of \t. So, how do I align the texts correctly?
CString szMsg;
szMsg.Format(_T("%s\t%s\t%s\r\n\r\n%s\t%s\t%s\r\n%s\t%s\t%s\r\n%s\t%s\t%s"),
_T("ITEM"), _T("VALUE"), _T("STATUS"),
_T("XXXXXXXX"), _T("1.0001"), _T("PASSED"),
_T("YYYYYYYYYYYYYYYY"), _T("-0.0001"), _T("FAILED"),
_T("ZZZ"), _T("0.0101"), _T("PASSED")
);
this->GetDlgItem(IDC_EDIT1)->SetWindowText(szMsg);
Note:
1. The strings would be generated during run-time, so it can be of any length.
2. I don't want to use ListCtrl or ListView because I should allow the user to do copy/paste the result.
I think you are using the wrong tool for the job here.
Since you need to present some tabular data to the user, I'd prefer using a control specifically designed for that, like the list-view control (in report mode). You could just have a dialog-box with a list-view control inside, and use it to present your data to the user.
Since you marked this question using the MFC tag, you can consider the CListCtrl class (or several other enhanced list-view control classes available for free on CodeProject).
If you really want to format some text in tabular data in a "console-mode" style, you may want to create a dialog-box with a static text control (or read-only edit control) inside, and set its font to something fixed-width (non-proportional); but I consider the former list-view control approach higher quality.
The proper way to display tabular data in the multi-line edit control is to set the tab stops prior to setting the text. See EM_SETTABSTOPS message
This is similar to the now forgotten typewriter tabs, where hitting the TAB key moves caret to the nearest tabstop to the right. You will not be able to right-align numeric data though; for that you'd need to use ListView.
I've made something like this,
#define TAB_WIDTH 56
/*codes skipped*/
CString szItems[4] = { _T("ITEM"), _T("XXXXXXXX"), _T("YYYYYYYYYYYYYYYY"), _T("ZZZ") };
CString szValues[4] = { _T("VALUE"), _T("1.0010"), _T("-0.0009"), _T("0.1001") };
CString szStatus[4] = { _T("STATUS"), _T("Passed"), _T("Failed"), _T("Passed") };
int nTabs[3][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
CDC *pDC = this->GetDC();
CFont *pOldFont = pDC->SelectObject(this->GetDlgItem(IDC_EDIT1)->GetFont());
SIZE sizeText;
for (int ni = 0; ni < 4; ni++)
{
GetTextExtentPoint32(pDC->GetSafeHdc(), szItems[ni], szItems[ni].GetLength(), &sizeText);
nTabs[0][ni] = sizeText.cx / TAB_WIDTH;
GetTextExtentPoint32(pDC->GetSafeHdc(), szValues[ni], szValues[ni].GetLength(), &sizeText);
nTabs[1][ni] = sizeText.cx / TAB_WIDTH;
GetTextExtentPoint32(pDC->GetSafeHdc(), szStatus[ni], szStatus[ni].GetLength(), &sizeText);
nTabs[2][ni] = sizeText.cx / TAB_WIDTH;
}
pDC->SelectObject(pOldFont);
int nBig[3] = { 0, 0, 0 };
nBig[0] = BiggestValue(nTabs[0], 4);
nBig[1] = BiggestValue(nTabs[1], 4);
nBig[2] = BiggestValue(nTabs[2], 4);
CString szDispStr = _T("");
for (int ni = 0; ni < 4; ni++)
{
szDispStr += szItems[ni];
for (int nj = nTabs[0][ni]; nj <= nBig[0]; nj++)
szDispStr += _T("\t");
szDispStr += szValues[ni];
for (int nj = nTabs[1][ni]; nj <= nBig[1]; nj++)
szDispStr += _T("\t");
szDispStr += szStatus[ni];
for (int nj = nTabs[2][ni]; nj <= nBig[2]; nj++)
szDispStr += _T("\t");
szDispStr += _T("\r\n");
if (ni == 0)
szDispStr += _T("\r\n");
}
this->GetDlgItem(IDC_EDIT1)->SetWindowTextW(szDispStr);
and the output is as expected
the edit control displayed
and the MessageBox() displayed
here TAB_WIDTH is the width of \t which I counted the pixels manually. Now I have to find the width of \t through code.