Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to read image files and store it in memory(std::string) in c++?

i've researched online for most of today but could not find the answer so i'm turning to stackoverflow for some suggestion.

basically, i have a c++ library that uses curl to perform PUT method to upload an image file. now this library takes a std::string for data. i have image files (like jpg, gif, png) on my local disk.

i don't care about contents of the file (as in, i don't do anything with it besides passing it to this library for PUT method). how can i read image files and store it in std::string? what if the file content contains NULL terminator?

i tried to add some of codes i've tried, but i'm new here and i'm not sure how to paste my code here in the right format. any help would be appreciated.

like image 783
Prod Tester Avatar asked Mar 08 '12 02:03

Prod Tester


3 Answers

Easiest method I can think of. Open the file in binary mode, then read the whole thing into a stringstream.

std::ifstream fin("foo.png", std::ios::in | std::ios::binary);
std::ostringstream oss;
oss << fin.rdbuf();
std::string data(oss.str());
like image 95
Benjamin Lindley Avatar answered Nov 16 '22 22:11

Benjamin Lindley


std::ifstream fin("foo.png", std::ios::binary);
std::string data;
data.reserve(1000000);
std::copy(std::istreambuf_iterator<char>(fin),
          std::istreambuf_iterator<char>(),
          std::back_inserter(data));

You can read image files to std::string with code like this. Adjust parameter for reserve method to be larger than 99% of your file sizes. Zero bytes (which you call NULL terminators) are treated correctly with both ifstream and string.


I've found a good article, where several methods of binary file loading are compared. Here is the fastest method from that article:

std::ifstream fin("foo.png", std::ios::binary);
fin.seekg(0, std::ios::end);
std::string data;
data.resize(fin.tellg());
fin.seekg(0, std::ios::beg);
fin.read(&data[0], data.size());

And here is the shortest one:

std::ifstream fin("foo.png", std::ios::binary);
std::string data((std::istreambuf_iterator<char>(fin)),
                 std::istreambuf_iterator<char>());

Update

Something like this may be used to feed the callback function (I didn't test it):

std::ifstream fin("foo.png", std::ios::binary);
fin.seekg(0, std::ios::end);
...
curl_easy_setopt(m_ctx, CURLOPT_INFILESIZE,    fin.tellg());
curl_easy_setopt(m_ctx, CURLOPT_READDATA,      (void *)&fin);
fin.seekg(0, std::ios::beg);
...
static size_t put_callback(void *ptr, size_t size, size_t nmemb, void *data){
  std::ifstream* in = static_cast<std::ifstream*>(data);
  if(in->eof()) return 0;
  in->read((char *)ptr, size*nmemb);
  return in->gcount();
}
like image 27
Evgeny Kluev Avatar answered Nov 16 '22 23:11

Evgeny Kluev


this is how the library makes PUT calls where 'data' is string passed in as file content

stringstream data_stream.str(data.c_str());
curl_easy_setopt(m_ctx, CURLOPT_UPLOAD,        1L);
curl_easy_setopt(m_ctx, CURLOPT_PUT,           1L);
curl_easy_setopt(m_ctx, CURLOPT_INFILESIZE,    data.length());
curl_easy_setopt(m_ctx, CURLOPT_READFUNCTION,  put_callback);
curl_easy_setopt(m_ctx, CURLOPT_READDATA,      (void *)&data_stream);
curl_easy_setopt(m_ctx, CURLOPT_WRITEFUNCTION, get_callback);
curl_easy_setopt(m_ctx, CURLOPT_WRITEDATA,     (void *)&m_request_response);

and here is the callback frunction for curlopt_readfunction

static size_t put_callback(void *ptr, size_t size, size_t nmemb, void *data){

  stringstream *output_stream;
  int          retval;

  output_stream = (stringstream *) data;

  if(output_stream->eof()) return 0;

  retval = min(size*nmemb,output_stream->str().size());
  output_stream->read((char *)ptr, retval);

  //return the number of bytes processed 
  return retval;
}
like image 2
Prod Tester Avatar answered Nov 17 '22 00:11

Prod Tester