File path from a usb camera - c++

Hello I am using GDI+ to do some image processing. I am having it run from the command line with two arguments. The reason for this is the program is being called from VBA Excel 2007. A Open file dialog is run from VBA and gives the first argument.
The first arguement is the original image to be processed and the second is where to save the image. Everything works just fine when the two arguments come from a drive with a letter, i.e. C:.
It was not working with network folders, i.e. \server\folder. I overcame this by mounting the folder to a drive letter before trying to load the image.
I have a problem now when the incoming image is on a usb camera. The file path of the file on the camera ends up being COMPUTER\Canon\DCIM\image.jpg. Windows is not mounting the camera to a lettered drive so it is not working correctly for me.
Before trying to load the image I add and extra '\' so that they are all double \.
I am not sure at all how to get this to work and have looked all over. Thanks.
int main(int argc, char* argv[])
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
// INITIALIZE GDI+
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
wchar_t tin[200] = L"";
wchar_t in[200] = L"";
wchar_t out[200] = L"";
wchar_t tout[200] = L"";
NETRESOURCE nr;
DWORD dwRetVal;
nr.dwType = RESOURCETYPE_DISK;
nr.lpLocalName = "M:";
nr.lpRemoteName = "\\\\server\\folder";
nr.lpProvider = NULL;
// Map the mugshots folder
dwRetVal = WNetAddConnection2(&nr, NULL, NULL, CONNECT_TEMPORARY);
// Convert to a wchar_t* from command line argument
size_t origsize = strlen(argv[1]) + 1;
mbstowcs( tin, argv[1], origsize);
//Add an extra \ for directory
int j = 0;
for (int i = 0 ; i < int(origsize) ; i++)
{
if(tin[i] == '\\')
{
in[j] = '\\';
j++;
in[j] = '\\';
j++;
}
else
{
in[j] = tin[i];
j++;
}
}
// Convert to a wchar_t* from command line argument
origsize = strlen(argv[2]) + 1;
mbstowcs(tout, argv[2], origsize);
//Add an extra \ for directory
out[0] = 'M';
out[1] = ':';
out[2] = '\\';
out[3] = '\\';
j = 4;
for (int i = 0 ; i < int(origsize) ; i++)
{
if(tout[i] == '\\')
{
out[j] = '\\';
j++;
out[j] = '\\';
j++;
}
else
{
out[j] = tout[i];
j++;
}
}
Bitmap b(in);
Process image
CLSID pngClsid;
GetEncoderClsid(L"image/jpeg", &pngClsid);
image2->Save(out, &pngClsid, NULL);
return 0;
}

Please take a look at the sample: GetImage Sample: Demonstrates the Windows Image Acquisition API:
The sample application has a single command on its File menu, named
From scanner or camera. When a WIA device (or a device emulator) is
attached, the menu item becomes enabled. When the user selects the
menu command, the sample will sequentially display the WIA Device
Selection dialog box, Image Selection dialog box, and Image Transfer
dialog box. The device and image selection dialog boxes are the common
dialog boxes supplied by the system, and the transfer dialog box is
implemented in this sample. Finally, the sample will display the
transferred image(s) in child window(s).
Hope this helps.

You need to look into how shell handles the special paths, a good start is here:
http://msdn.microsoft.com/en-us/library/bb773559%28v=vs.85%29.aspx
For a lot of what you are doing, you should be using PathCanonicalize() or something along these lines.
Unsure if this helps you with your camera, you may need to access image acquisition APIs directly to get files out of some cameras.

Related

How does one tell Windows 10 to tile, center, or stretch desktop wallpaper using WIN32 C/C++ API?

Goal: using C++, the Win32 SDK and Visual Studio 2019 to set the desktop wallpaper to be centered or tiled or stretched.
One can use SystemParametersInfo() to change the wallpaper. No problem at all.
Problem is telling the system to tile or center or stretch the wallpaper image.
Reading on the web, whether the wallpaper image is centered, tiled or stretched depends on a pair of registry entries:
HKCU\Control Panel\Desktop\TileWallpaper
HKCU\Control Panel\Desktop\WallpaperStyle
MS' WIN32 docs tell how to change the image but I can't find anything describing how to change the layout.
I have the following code. It is a console app project, the functions ripped out of my larger MFC app, thus the function names. This project's character set is set to Unicode, thus my use of W functions.
It does change the wallpaper image, but the wallpaper is always tiled, regardless of which of the onWallpaper___() functions are called.
Windows seems to completely ignore the registry changes. I have verified that my code does indeed change the registry entries' values.
Question: How does one tell Windows 10 to tile, center, or stretch desktop wallpaper using WIN32 C/C++ API?
Question: Are there different registry entries that should be used?
#include <Windows.h>
#include <iostream>
#include <string>
#include <cassert>
const int CENTERED = 0;
const int TILED = 1;
const int STRETCHED = 2;
void set_wallpaper_registry_keys(int discriminant) {
BOOL rtn;
HKEY hKey;
DWORD TileWallpaper = 0;
DWORD WallpaperStyle = 0;
switch (discriminant) {
case CENTERED: {
TileWallpaper = 0;
WallpaperStyle = 1; // some sources say use 6, makes no difference.
}
break;
case TILED: {
TileWallpaper = 1;
WallpaperStyle = 0;
}
break;
case STRETCHED: {
TileWallpaper = 0;
WallpaperStyle = 2;
}
break;
default: {
assert(false);
}
break;
}
std::wstring key_name(L"Control Panel\\Desktop");
rtn = RegOpenKeyEx(HKEY_CURRENT_USER, key_name.c_str(), 0, KEY_ALL_ACCESS, &hKey);
assert(rtn == ERROR_SUCCESS);
rtn = RegSetValueEx(hKey, L"TileWallpaper", 0, REG_DWORD, (BYTE *)&TileWallpaper, sizeof(DWORD));
assert(rtn == ERROR_SUCCESS);
rtn = RegSetValueEx(hKey, L"WallpaperStyle", 0, REG_DWORD, (BYTE *)&WallpaperStyle, sizeof(DWORD));
assert(rtn == ERROR_SUCCESS);
rtn = RegFlushKey(hKey);
assert(rtn == ERROR_SUCCESS);
rtn = RegCloseKey(hKey);
assert(rtn == ERROR_SUCCESS);
}
void OnWallpaperCentered() {
BOOL rtn;
set_wallpaper_registry_keys(CENTERED);
// set current image as wallpaper: SPI_SETDESKWALLPAPER
std::wstring fn = L"c:\\tmp\\stars.jpg";
rtn = SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (void *) (fn.c_str()), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
assert(rtn == TRUE);
}
void OnWallpaperTiled() {
// TODO: Add your command handler code here
BOOL rtn;
set_wallpaper_registry_keys(TILED);
std::wstring fn = L"c:\\tmp\\snail.jpg";
rtn = SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (void *) (fn.c_str()), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
assert(rtn == TRUE);
}
void OnWallpaperStretched() {
// TODO: Add your command handler code here
BOOL rtn;
set_wallpaper_registry_keys(STRETCHED);
std::wstring fn = L"c:\\tmp\\civ4.jpg";
rtn = SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (void*) (fn.c_str()), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
assert(rtn == TRUE);
}
int main() {
//OnWallpaperTiled(); // Tiles the wallpaper
OnWallpaperCentered(); // Tiles the wallpaper as well
//OnWallpaperStretched(); // Tiles the wallpaper too
std::cout << "Hello World!\n";
}
Try IDesktopWallpaper interface and IActiveDesktop interfaces.
Create objects for them by creating CLSID_DesktopWallpaper and CLSID_ActiveDesktopobjects.

GetOpenFileName with SDL2

I wrote a c++ app using SDL2 to simulate an editBox. It worked ok untill i added a function to open and select a file on Windows explorer.
Precisely after i click "Open" on the file browser, i can not use TTF_OpenFont() anymore...
I am still able to use TextSprites i have declared at the initialisation but i can't change the string associate to them no more. And that's really annoying because my editBox have to display a string var in my main loop.
I've already checked my font path with debug break points and it didn't change (still the same absolute path) nor the font size.
I've tryed many things to solve this : use another .ttf, use another TTF_Font *var, ect
Also tryed to put my openfiledialog function in a separate thread, that didn't change anything, so i tryed to control the new thread with windows Events and then with Sdl_Event but had no luck.
I obviously spent hours and hours of testing searching the web for similar issues and found nothing but unsolved posts.
Here is the funtion that allows me to get the name of the file opened :
void CMain::changeDirectoryPath()
{
OPENFILENAME ofn;
TCHAR szFile[MAX_PATH];
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFile = szFile;
ofn.lpstrFile[0] = '\0';
ofn.hwndOwner = NULL;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = TEXT("Text Files\0*.txt\0Any File\0*.*\0");
ofn.nFilterIndex = 1;
ofn.lpstrTitle = TEXT("Select dictionary");
ofn.lpstrInitialDir = L"data\\dictionary";
ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST;
if(GetOpenFileName(&ofn))
{
OutputDebugString(ofn.lpstrFile);
int cSize = WideCharToMultiByte (CP_ACP, 0, ofn.lpstrFile, wcslen(ofn.lpstrFile), NULL, 0, NULL, NULL);
string output(static_cast<size_t>(cSize), '\0');
WideCharToMultiByte (CP_ACP, 0, ofn.lpstrFile, wcslen(ofn.lpstrFile), reinterpret_cast<char*>(&output[0]), cSize, NULL, NULL);
cout<<output<<endl;
}
cdpOn = false;
}
And the one that used to change the text displayed on my TextSprite :
bool CDictionary::loadFromRenderedText(std::string textureText)
{
if(Message!=NULL)
{
SDL_DestroyTexture(Message);
Message = NULL;
TTF_CloseFont(font);
}
font = TTF_OpenFont(filePath.c_str(), policeSize);
if(!font)
{
cout<<"TTF_OpenFont: "<<TTF_GetError()<<endl;
return 0;
}
textSurface = TTF_RenderText_Solid(font, textureText.c_str(), textColor);
if(textSurface != NULL)
{
Message = SDL_CreateTextureFromSurface(renderer, textSurface);
if(Message==NULL)
{
printf("Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError());
}
else
{
position.x=50;
position.y=50;
position.w=textSurface->w;
position.h=textSurface->h;
}
SDL_FreeSurface(textSurface);
}
else
{
printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
}
return Message != NULL;
}
At last i thought to add WxWidget in my project and use wxFileDialog to see if it solve the problem but i'm affraid mixing SDL2 and wxWidget will resort in a savage mess :-(
Does anybody knows why i can not reopen a tt_font after i select and open a file with GetOpenFileName()?
Or have suggestion to possibly solve this?
Thanks in advance
Comment under this functions MSDN page says "Current Working Directory is altered when a file is opened", which is exactly what you're describing. Revert it back with SetCurrentDirectory (query at launch with GetCurrentDirectory, once).
Another way would be not closing the font since you're using it quite often.

Creating 8 bit bitmap from array of numbers

This has been bugging me for some time, I want to make sure that my understanding of bitmaps is correct and get some help spotting errors. Basically what I am trying to do is to save an 8 bit bitmap file and at the same time display it in a picture box in the MFC application. I want to avoid the cumbersome method of saving the bitmap then loading it up again.
The saving file operation was mostly successful, however I altered my code and now what used to be white in the file (in this instance its a black and white image) is coming out usually green but it changes. I'm guessing this is because my data is referencing information in the color table possibly, which value would be white?
HBITMAP ReadWrite::SaveFile(LPCTSTR file, double* data) {
BYTE* bmp = ConvertData(data);
HANDLE hf;
BITMAPINFO* pbmi = WriteHeader(file);
BITMAPFILEHEADER* bmfh = (BITMAPFILEHEADER*)alloca(sizeof(BITMAPFILEHEADER));
bmfh->bfType = 0x4d42; // 'BM'
bmfh->bfReserved1 = 0;
bmfh->bfReserved2 = 0;
bmfh->bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbmi->bmiHeader.biSize + 256 * sizeof(RGBQUAD);
bmfh->bfSize = (DWORD)(bmfh->bfOffBits + pbmi->bmiHeader.biSizeImage);
hf = CreateFile(file, GENERIC_READ | GENERIC_WRITE, (DWORD) 0,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL );
if (hf == NULL) // error creating
{
CloseHandle (hf);
return NULL;
}
// write header
unsigned long bwritten;
if (!WriteFile(hf, (LPCVOID)bmfh, sizeof(BITMAPFILEHEADER), &bwritten, NULL))
{
CloseHandle (hf);
return NULL;
}
// write infoheader
if (!WriteFile(hf, (LPCVOID)pbmi, sizeof (BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD), &bwritten, NULL ))
{
CloseHandle (hf);
return NULL;
}
// write image data
if (!WriteFile(hf, (LPCVOID)bmp_data, (int) pbmi->bmiHeader.biSizeImage, &bwritten, NULL ))
{
CloseHandle (hf);
return NULL;
}
// Close
CloseHandle(hf);
// Send back a file to display
return CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, (void**)bmp_data, NULL, 0);
}
Code to write the infoheader + palette (which should be values ranging from black to white??)
BITMAPINFO* ReadWrite::WriteHeader(LPCTSTR fn)
{
int R = ReadWrite::getR();
int C = ReadWrite::getC();
BITMAPINFO* pbmi = (BITMAPINFO*)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256);
pbmi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = R;
pbmi->bmiHeader.biHeight = -C;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 8;
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = (((R * pbmi->bmiHeader.biBitCount + 31) & ~31) >> 3) * C;
pbmi->bmiHeader.biClrUsed = 256;
pbmi->bmiHeader.biClrImportant = 0;
for(int i=0; i<256; i++)
{
pbmi->bmiColors[i].rgbRed = i;
pbmi->bmiColors[i].rgbGreen = i;
pbmi->bmiColors[i].rgbBlue = i;
pbmi->bmiColors[i].rgbReserved = 0;
}
//return true;
return pbmi;
}
And finally converting my number array into unsigned char 'Bytes':
BYTE* ReadWrite::ConvertData(double* data) {
BYTE* bmp_data;
int R = ReadWrite::getR();
int C = ReadWrite::getC();
bool binary = ReadWrite::getBinary();
bmp_data = new BYTE [R*C];
// convert the values to unsigned char (BYTE)
for(int i=0; i<R*C; i++){
if (data[i] == 1){
data[i] = 255;
}
bmp_data[i] = (unsigned char)data[i];
}
delete [] data;
return bmp_data;
}
So a recap of the issues/questions:
White comes out lime green.
The HBITMAP is unable to display inside a picturebox, the box goes solid black after setimage called (yes its set to SS_BITMAP)
I believe I may be missing some information from the creation of the bitmap and I think I need to implement a device context though I'm unsure. I can open the file in windows but if I try to upload it online it doesnt like the format.
I don't know how to manage the memory of the objects, so I'm getting leaks, how do I clean up with DeleteObject just before the application closes? (destructor of dialog maybe?) The leaks are 262144 bytes which is around the size of the image.
Thanks for reading this stupid long post.
EDIT I managed to fix the green issue (number 1), I don't know how, I think it was to do with incorrect sizes for memory on the headers. It still isn't able to upload to the internet or display in the program so something must be wrong with it.
So I found the issue with my code that was causing errors across other applications/the internet.
In it I assign a negative value to the height of the image in order to flip the data, however this is a completely incorrect solution. Instead:
// convert the integer values to unsigned char (BYTE) BACKWARDS
for(int i=0; i<R; i++){
for(int j=0; j<C; j++){
if (data[i*R + j] == 1 && binary){
data[i*R + j] = 255;
}
bmp_data[(R-i)*C + (j-C)] = (unsigned char)data[i*C + j];
}
}
What this does is copies the original values into the bmp_data both backwards and flipped. This ensures the data is stored correctly and will open in the application. My current solution to DIBSection and memory management was to delete all the data and reload the image from file instead. Passing a HBITMAP was too much of a chore. I would welcome input on that part, but for now all my problems are fixed.

updating jpeg properties in c++ using GDI+

I am tring to copy properties from one jpeg image to another in c++. As I don't have any library and I am working on windows, I am using GDI+ for this.
My code is as follow
void CopyJpegProperties(string targetImageName,string sourceImageName)
{
CLSID m_clsid;
EncoderParameters m_encoderParameters;
UINT size;
UINT count;
int quality=100;
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR m_gdiplusToken;
// start GDI+
GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
{
// we are processing images inside a block to make sure that all of objects are deleted when GDI is shutdown.
// read source image properties
std::wstring wcSourceImageName=StringTools::StringToWString(sourceImageName);
Gdiplus::Bitmap sourceBitmap(wcSourceImageName.c_str());
sourceBitmap.GetPropertySize(&size, &count);
PropertyItem* pPropBuffer =(PropertyItem*)malloc(size);
sourceBitmap.GetAllPropertyItems(size, count, pPropBuffer);
// write to target image
std::wstring wcTargetImageName=StringTools::StringToWString(targetImageName);
Gdiplus::Bitmap targetBitmap(wcTargetImageName.c_str());
for(int i=0; i<count; i++)
{
targetBitmap.SetPropertyItem(&pPropBuffer[i]);
}
JpegTools::GetEncoderClsid(L"image/jpeg", &m_clsid);
m_encoderParameters.Count = 1;
m_encoderParameters.Parameter[0].Guid = EncoderQuality;
m_encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
m_encoderParameters.Parameter[0].NumberOfValues = 1;
m_encoderParameters.Parameter[0].Value = &quality;
Status stat = targetBitmap.Save(wcTargetImageName.c_str(), &m_clsid, &m_encoderParameters);
if(stat != Ok)
{
throw exception("Error in saving");
}
}
GdiplusShutdown(m_gdiplusToken);
}
This function fails with error code 7 which win32error.
I think the problem is that when I open the target file I can not write to it as it is locked by open function.
How can I fix it?
Is there any better way to read/write image properties in windows?

C++/Win32 Finding all keyboard input languages?

I want to find all the input languages for the keyboard, the ones that you switch between with LEFT ALT + SHIFT.
I can get the default locale and the installed/supported locales with win API but I could not find anywhere anything about the input locales for the keyboard.
You have to use GetKeyboardLayoutList function.
For example, to output in console all keyboard input languages you can use this code:
UINT uLayouts;
HKL *lpList = NULL;
wchar_t szBuf[512];
uLayouts = GetKeyboardLayoutList(0, NULL);
lpList = (HKL*)LocalAlloc(LPTR, (uLayouts * sizeof(HKL)));
uLayouts = GetKeyboardLayoutList(uLayouts, lpList);
for(int i = 0; i < uLayouts; ++i)
{
GetLocaleInfo(MAKELCID(((UINT)lpList[i] & 0xffffffff),
SORT_DEFAULT), LOCALE_SLANGUAGE, szBuf, 512);
wprintf(L"%s\n", szBuf);
memset(szBuf, 0, 512);
}
if(lpList)
LocalFree(lpList);