I am working on an MFC app that uses CDHtmlDialog class to create a dynamic HTML page.
Now i want to pass/stream a image pointer to the HTML page to show it to the users.
The image will be stored in the hard disk, and the MFC should have a way of streaming this to the HTML page for display on a particular user event.
I am not sure how to convert a JPG or GIF file into something else that i can pass to the HTML page.
Possibly as an argument to JavaScript function residing in the HTML page.
Any help is welcome. Please guide with sample codes.
Thanks in advance.
Firstly, refer to How to display Base64 images in HTML?. Then encode the image data using the following function. Hope this help!
string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i <4); i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while ((i++ < 3))
ret += '=';
}
return ret;
}
Related
I need to convert base64 to opencv::mat file. So I took a set of 10 frames from a video and appended base64(A)(using base64.b64encode in python).
After that, I used the code from here to convert that base64 to Mat. Images looked fine.
But they have larger file size than the original images, plus when I encoded these final images to base64(B)(using base64.b64encode in python), the encoded base64 is different from original base64(A). I can't understand why? This is also affecting the output of my application that is using the cv::mat output.
For base64 to Mat I am using code from here(asposted above).
Edited: Following is my python script to convert set of jpeg to base64 (.txt)
def img2txt(file_directory):
imageFiles = glob.glob(file_directory+"/*.jpg")
imageFiles.sort()
fileWrite='base64encoding.txt'
#print fileWrite
for i in range(0,len(imageFiles)):
image = open(imageFiles[i],'rb')
image_read = image.read()
image_64_encode = base64.b64encode(image_read)
with open (fileWrite, 'a') as f:
f.writelines(image_64_encode+'\n')
base64decode function : from here
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4) {
for (i = 0; i < 4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
/*for (j = i; j < 4; j++)
char_array_4[j] = 0;*/
for (j = 0; j < i; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
//char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++)
ret += char_array_3[j];
}
return ret;
}
C++ Main function:
int main()
{
ifstream in("TestBase64.txt");
if(!in) {
cout << "Cannot open input file.\n";
return 1;
}
int i=0;
string encoded_string;
while (getline(in, encoded_string))
{
string decoded_string = base64_decode(encoded_string);
vector<uchar> data(decoded_string.begin(), decoded_string.end());
cv::imwrite("/Frames_from_B_to_Mat/Frames_from_B_to_Mat"+b+".jpg");
i++;
}
return 0;
}
On the line:
vector<uchar> data(decoded_string.begin(), decoded_string.end());
you are presumably holding the JPEG-encoded representation of one image in data. So you may as well just write this to a binary file, rather than use cv::imwrite() which is for writing a Mat to a file.
If, for some inexplicable reason, you want to use cv::imwrite(), you need to pass it a Mat. So you would end up decoding the JPEG representation to a Mat and then encoding to JPEG and writing - which seems silly:
cv::Mat img = cv::imdecode(data, cv::IMREAD_COLOR);
cv::imwrite('result.jpg',img);
TLDR;
What I'm saying is that your data is already JPEG-encoded, you read it from a JPEG file.
My server holds jpeg-file in std::string buffer (ANSI). I need to send it to web-client on request. I tried next:
std::string ws_encode(std::string frame) {
string result;
result.resize(2);
result[0]= 130;
if (frame.size() <= 125) {result[1]=frame.size();}
else if (frame.size() >= 126 && frame.size() <= 65535) {
result.resize(4);
result[1] = 126;
result[2] = ( frame.size() >> 8 ) && 255;
result[3] = ( frame.size() ) && 255;
}
else {
result.resize(10);
result[1] = 127;
result[2] = ( frame.size() >> 56 ) && 255;
result[3] = ( frame.size() >> 48 ) && 255;
result[4] = ( frame.size() >> 40 ) && 255;
result[5] = ( frame.size() >> 32 ) && 255;
result[6] = ( frame.size() >> 24 ) && 255;
result[7] = ( frame.size() >> 16 ) && 255;
result[8] = ( frame.size() >> 8 ) && 255;
result[9] = ( frame.size() ) && 255;
}
return result+frame;
}
And then:
string encoded_frame = ws_encode(Agents["65535"].Screen); // it's a map <string id, struct Agent>, Agent has string Screen buffer for screenshots
send(client_socket, &encoded_frame[0], encoded_frame.size(), 0);
But the browser closes the connection without any explanations in console. Maybe length calculation is wrong, or not all data was sent... I don't know - writing test.txt with encoded data before send looks correct.
Could anybody help me in this task?
When setting up the bytes of the payload length value, you are using the LOGICAL AND (&&) operator when you should be using the BITWISE AND (&) operator instead.
Try something more like this instead:
std::string ws_encode(char opcode, const std::string &data)
{
string result;
std::string::size_type size = data.size();
if (size <= 125)
{
result.resize(2+size);
result[0] = 0x80 | opcode;
result[1] = (char) size;
}
else if (size <= 65535)
{
result.resize(4+size);
result[0] = 0x80 | opcode;
result[1] = 126;
result[2] = (size >> 8) & 0xFF;
result[3] = (size ) & 0xFF;
}
else
{
result.resize(10+size);
result[0] = 0x80 | opcode;
result[1] = 127;
result[2] = (size >> 56) & 0xFF;
result[3] = (size >> 48) & 0xFF;
result[4] = (size >> 40) & 0xFF;
result[5] = (size >> 32) & 0xFF;
result[6] = (size >> 24) & 0xFF;
result[7] = (size >> 16) & 0xFF;
result[8] = (size >> 8) & 0xFF;
result[9] = (size ) & 0xFF;
}
if (size > 0)
{
memcpy(&result[result.size()-size], data.c_str(), size);
// or:
// std::copy(data.begin(), data.end(), result.begin()+(result.size()-size));
}
return result;
}
std::string encoded_frame = ws_encode(0x02, Agents["65535"].Screen);
send(client_socket, encoded_frame.c_str(), encoded_frame.size(), 0);
I am working on getting someone else's code up and running. The code is written in C++. The part that is failing is when it converts a std::string to base64:
std::string tmp = "\0";
tmp.append(strUserName);
tmp.append("\0");
tmp.append(strPassword);
tmp = base64_encode(tmp.c_str(), tmp.length());
where base64 is:
std::string base64_encode(char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
It uses the 'tmp' string to make a call to a server and it's imperative that the base64 string has the two NUL characters embedded within it (before strUserName and before strPassword). However, it seems that since the code is passing tmp as a c_str(), the NUL characters are being stripped. Is there a good solution for this? Thanks.
Update I guess I should add that the code includes "#include <asm/errno.h>" which I googled for and didn't find compatibility for macOS so I just commented it out.. Not sure if that is making things not work but I doubt it. Full disclosure.
std::string tmp = "\0"; and tmp.append("\0"); don't add any '\0' characters to tmp. The versions of std::string::string and std::string::append that take a const char* take a NUL-terminated C-style string, so they stop as soon as they see a NUL character.
To actually add a NUL character to your string, you'll need to use the constructor and append methods that take a length along with a const char*, or the versions that take a count and a char:
std::string tmp("\0", 1);
tmp.append(strUserName);
tmp.append("\0", 1);
tmp.append(strPassword);
tmp = base64_encode(tmp.c_str(), tmp.length());
I have an opencv image and I want to convert it to a base46 string so I can serialize it.
I have this code:
std::vector<char> convertImageToChar(cv::Mat image)
{
std::stringstream os;
int imageSize = image.size().area() * image.elemSize1();
typedef boost::archive::iterators::base64_from_binary<const char *> base64_text; // compose all the above operations in to a new iterator
std::vector<char> output(base64_text(image.data), base64_text(image.data + imageSize));
return output;
}
The code compiles well, but I am getting error during run time: expression t<64 on line 51 on base64_from_binary.
What is the problem and how I can fix it?
I have no experience with boost base64_text, so in the following I refer to this code for base64 related stuff. It should be straightforward to port to boost, if needed.
Aside from boost related stuff, there are a few problems with your implementation:
You don't take into account that an image may not be continuous.
You won't know how to recover the original image, since you don't encode image size, type and channels.
You can take a look at the following code and how data is managed in the function mat2str and str2mat. This will handle arbitrary Mat type. Their code is an adaptation from here:
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
// Code from: http://www.adp-gmbh.ch/cpp/common/base64.html
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(uchar const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i <4); i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while ((i++ < 3))
ret += '=';
}
return ret;
}
std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}
string mat2str(const Mat& m)
{
Mat src;
if (!m.isContinuous()) {
src = m.clone();
}
else {
src = m;
}
// Create header
int type = m.type();
int channels = m.channels();
vector<uchar> data(4*sizeof(int));
memcpy(&data[0 * sizeof(int)], (uchar*)&m.rows, sizeof(int));
memcpy(&data[1 * sizeof(int)], (uchar*)&m.cols, sizeof(int));
memcpy(&data[2 * sizeof(int)], (uchar*)&type, sizeof(int));
memcpy(&data[3 * sizeof(int)], (uchar*)&channels, sizeof(int));
// Add image data
data.insert(data.end(), m.datastart, m.dataend);
// Encode
return base64_encode(data.data(), data.size());
}
Mat str2mat(const string& s)
{
// Decode data
string data = base64_decode(s);
// Decode Header
int rows;
int cols;
int type;
int channels;
memcpy((char*)&rows, &data[0 * sizeof(int)], sizeof(int));
memcpy((char*)&cols, &data[1 * sizeof(int)], sizeof(int));
memcpy((char*)&type, &data[2 * sizeof(int)], sizeof(int));
memcpy((char*)&channels, &data[3 * sizeof(int)], sizeof(int));
// Make the mat
return Mat(rows, cols, type, (uchar*)&data[4*sizeof(int)]).clone();
}
int main()
{
string encoded;
{
Mat3b m(100, 100, Vec3b(0, 0));
circle(m, Point(50, 50), 25, Scalar(0, 255, 0));
imshow("Original", m);
waitKey(1);
encoded = mat2str(m);
}
Mat decoded = str2mat(encoded);
imshow("Reconstructed", decoded);
waitKey();
return 0;
}
I should note that this program is adhering (at least, trying to) to the Tiled API.
I'm trying to use the uncompress() function in zlib, but for some reason my program crashes whenever I call the function. This is what I have, and all of the parameters look right, so I'm not really sure what the problem is.
// const char* filedata passed in function is Zlib compressed and Base64 encoded
uLong inLen = static_cast<uLong>((strlen(filedata)*6)/8); // Calculate the length
std::string inBuffer = BASE64_DECODE(filedata); // My data
uLongf outLen = static_cast<uLongf>(width*height*4); // Tiled API specification
Bytef* outBuffer = new Bytef(outLen); // Destination
int ret = uncompress(outBuffer, &outLen,
reinterpret_cast<Bytef*>(&inBuffer[0]), inLen);
ret returns nothing, the program crashes. Does anybody have any ideas? Here is the BASE64_DECODE function:
std::string BASE64_DECODE(std::string const& encoded_string)
{
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while(in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
{
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4)
{
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if(i)
{
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}
EDIT: If you're looking at this in the future, make sure you delete the outBuffer variable later in the program to prevent memory leaks.
Bytef isn't used with a constructor that takes a length argument. You probably meant Bytef* outBuffer = new Bytef[outLen]; (square brackets).
I think Bytef is usually typedef-ed to some primitive type anyway, so using it is analogous to something like new int[len] or new uint64_t[len].