Exiv2: How to read photo with UTF8 filepath? - c++

I am using GTKmm and exiv2 to read EXIF metadata form photos. However Exiv2 functions accept only std::string file paths... When I try it on not ASCII filepath it crushes the program.
Is there any way to read that data? It would be great if Exiv2 accepted Glib::ustrings...
I'm interested in solutions for Windows and Linux.

Ok, I have a solution!
You just need to use function Glibmm::locale_from_utf8 to convert UTF8 string to std(ascii) string.
Here is an example:
void get_exif_data(const Glib::ustring &image_src)
{
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(Glib::locale_from_utf8(image_src));
image->readMetadata();
Exiv2::ExifData &exifData = image->exifData();
Exiv2::ExifData::const_iterator it = exifData.begin();
for(it;it!=exifData.end();it++) cout << it->key() + ": " + it->getValue() << endl;
}

If this is in Windows then you can use GetShortPathName.

Related

toBase64 encoding in Qt does not result in a printable QString

I've replicated this in two places in my code, one written by me and the one I'm posting an image of, that was written by someone else. I can't get the base64 to output to qDebug at all. I thought base64 was supposed to be readable. It has a size. But it won't print the entire qDebug line.
Thanks in advance for any help.
Here's the code. I'm on Qt Kit 5.12.1 64 bit mingw in release.
QFile* file = new QFile("C:\\Qr-Pic\\Poll_Directory\\IMG_00000001 - Copy (53).jpg");
file->open(QIODevice::ReadOnly);
QByteArray image = file->readAll();
int originalSize = image.length();
QString encoded = QString(image.toBase64());
int encodedSize = encoded.size();
qDebug() << "encodedSize=" << encodedSize;
qDebug() << "encode=" << encoded;
Output:
encodedSize= 34036

How to append a variable in to the output file's name in C++

I have a C++ project which output data in to a file. The following is the code for it.
case 3:
{
outfile.open("price-change.csv");
if(! outfile)
{
cout << "Can not open outfile" << endl;
exit(1);
}
i want to mutate the file name as price-change-2014-12-23 where 2014-12-23 is a variable added to the file name, price change. Any idea guys? Thanks in advance.
std::string filename = "price-change-" + datestring + ".csv"
outfile.open(filename);
Should do it.
Thomas Matthews points out in the comments that older compilers and compilers without C++11 support enabled the file must be opened with a const char * rather than a std::string. If the above produces an error message and C++11 cannot be used, open the file with
outfile.open(filename.c_str());
And if you have numbers like integers or floats involved you can use stringstream to build up your datestring easily.

opening output filestreams with string names

Hi I have some C++ code that uses user defined input to generate file-names for some output files:
std::string outputName = fileName;
for(int i = 0; i < 4; i++)
{
outputName.pop_back();
}
std::string outputName1 = outputName;
std::string outputName2 = outputName;
outputName.append(".fasta");
outputName1.append("_Ploid1.fasta");
outputName2.append("_Ploid2.fasta");
Where fileName could be any word the user can define with .csv after it e.g. '~/Desktop/mytest.csv'
The code chomps .csv off and makes three filenames / paths for 3 output streams.
It then creates them and attempts to open them:
std::ofstream outputFile;
outputFile.open(outputName.c_str());
std::ofstream outputFile1;
outputFile1.open(outputName1.c_str());
std::ofstream outputFile2;
outputFile2.open(outputName2.c_str());
I made sure to pass the names to open as const char* with the c_str method, however if I test my code by adding the following line:
std::cout << outputFile.is_open() << " " << outputFile1.is_open() << " " << outputFile2.is_open() << std::endl;
and compiling and setting fineName as "test.csv". I successfully compile and run, however,
Three zeros's are printed to screen showing the three filestreams for output are not in fact open. Why are they not opening? I know passing strings as filenames does not work which is why I thought conversion with c_str() would be sufficient.
Thanks,
Ben W.
Your issue is likely to be due to the path beginning with ~, which isn't expanded to /{home,Users}/${LOGNAME}.
ifstream open file C++
This answer to How to create a folder in the home directory? may be of use to you.
Unfortunately, there is no standard, portable way of finding out exactly why open() failed:
Detecting reason for failure to open an ofstream when fail() is true
I know passing strings as filenames does not work which is why I thought conversion with c_str() would be sufficient.
std::basic_ofstream::open() does accept a const std::string & (since C++11)!

How to save a CSV file as UTF-8

I write the code to create the . CSV files out there with Thai characters. But when I open a file using Microsoft Excel Thai characters in that file a wrong.But when I open it in Notepad, and then I press Save. And open it in Excel again. It is desired I think it is because the program does not Encoding to utf-8.
I had to do to Program, save it as utf-8.
std:: ofstream MyCSVFile;
MyCSVFile.open("myfile.csv", std::ios::out | std::ios::app);
MyCSVFile << "Name,Address" << endl;
MyCSVFile <<name<<","<<address << endl;
MyCSVFile.close();
}
You need to write the BOM to the beginning of the file. Try this:
const char *bom = "\xef\xbb\xbf";
MyCSVFile << bom;
MyCSVFile << "Name...
This a good read: BOM in Wikipedia.
You need to do the following (assuming the file path is stored in FilePath):
Here is the code you should use:
const std::wstring fileStr(FilePath);
wofstream mFile(FilePath);
mFile.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));
if (mFile.is_open())
{
const wchar_t *bom = L"\xef\xbb\xbf";
mFile << bom;
...
Now you can write the text, and of course close the file.

C++ - string.compare issues when output to text file is different to console output?

I'm trying to find out if two strings I have are the same, for the purpose of unit testing. The first is a predefined string, hard-coded into the program. The second is a read in from a text file with an ifstream using std::getline(), and then taken as a substring. Both values are stored as C++ strings.
When I output both of the strings to the console using cout for testing, they both appear to be identical:
ThisIsATestStringOutputtedToAFile
ThisIsATestStringOutputtedToAFile
However, the string.compare returns stating they are not equal. When outputting to a text file, the two strings appear as follows:
ThisIsATestStringOutputtedToAFile
T^#h^#i^#s^#I^#s^#A^#T^#e^#s^#t^#S^#t^#r^#i^#n^#g^#O^#u^#t^#p^#u^#t^#
t^#e^#d^#T^#o^#A^#F^#i^#l^#e
I'm guessing this is some kind of encoding problem, and if I was in my native language (good old C#), I wouldn't have too many problems. As it is I'm with C/C++ and Vi, and frankly don't really know where to go from here! I've tried looking at maybe converting to/from ansi/unicode, and also removing the odd characters, but I'm not even sure if they really exist or not..
Thanks in advance for any suggestions.
EDIT
Apologies, this is my first time posting here. The code below is how I'm going through the process:
ifstream myInput;
ofstream myOutput;
myInput.open(fileLocation.c_str());
myOutput.open("test.txt");
TEST_ASSERT(myInput.is_open() == 1);
string compare1 = "ThisIsATestStringOutputtedToAFile";
string fileBuffer;
std::getline(myInput, fileBuffer);
string compare2 = fileBuffer.substr(400,100);
cout << compare1 + "\n";
cout << compare2 + "\n";
myOutput << compare1 + "\n";
myOutput << compare2 + "\n";
cin.get();
myInput.close();
myOutput.close();
TEST_ASSERT(compare1.compare(compare2) == 0);
How did you create the content of myInput? I would guess that this file is created in two-byte encoding. You can use hex-dump to verify this theory, or use a different editor to create this file.
The simpliest way would be to launch cmd.exe and type
echo "ThisIsATestStringOutputtedToAFile" > test.txt
UPDATE:
If you cannot change the encoding of the myInput file, you can try to use wide-chars in your program. I.e. use wstring instead of string, wifstream instead of ifstream, wofstream, wcout, etc.
The following works for me and writes the text pasted below into the file. Note the '\0' character embedded into the string.
#include <iostream>
#include <fstream>
#include <sstream>
int main()
{
std::istringstream myInput("0123456789ThisIsATestStringOutputtedToAFile\x0 12ou 9 21 3r8f8 reohb jfbhv jshdbv coerbgf vibdfjchbv jdfhbv jdfhbvg jhbdfejh vbfjdsb vjdfvb jfvfdhjs jfhbsd jkefhsv gjhvbdfsjh jdsfhb vjhdfbs vjhdsfg kbhjsadlj bckslASB VBAK VKLFB VLHBFDSL VHBDFSLHVGFDJSHBVG LFS1BDV LH1BJDFLV HBDSH VBLDFSHB VGLDFKHB KAPBLKFBSV LFHBV YBlkjb dflkvb sfvbsljbv sldb fvlfs1hbd vljkh1ykcvb skdfbv nkldsbf vsgdb lkjhbsgd lkdcfb vlkbsdc xlkvbxkclbklxcbv");
std::ofstream myOutput("test.txt");
//std::ostringstream myOutput;
std::string str1 = "ThisIsATestStringOutputtedToAFile";
std::string fileBuffer;
std::getline(myInput, fileBuffer);
std::string str2 = fileBuffer.substr(10,100);
std::cout << str1 + "\n";
std::cout << str2 + "\n";
myOutput << str1 + "\n";
myOutput << str2 + "\n";
std::cout << str1.compare(str2) << '\n';
//std::cout << myOutput.str() << '\n';
return 0;
}
Output:
ThisIsATestStringOutputtedToAFile
ThisIsATestStringOutputtedToAFile
It turns out that the problem was that the file encoding of myInput was UTF-16, whereas the comparison string was UTF-8. The way to convert them with the OS limitations I had for this project (Linux, C/C++ code), was to use the iconv() functions. To keep the compatibility of the C++ strings I'd been using, I ended up saving the string to a new text file, then running iconv through the system() command.
system("iconv -f UTF-16 -t UTF-8 subStr.txt -o convertedSubStr.txt");
Reading the outputted string back in then gave me the string in the format I needed for the comparison to work properly.
NOTE
I'm aware that this is not the most efficient way to do this. I've I'd had the luxury of a Windows environment and the windows.h libraries, things would have been a lot easier. In this case though, the code was in some rarely used unit tests, and as such didn't need to be highly optimized, hence the creation, destruction and I/O operations of some text files wasn't an issue.