image won't open

Pages: 12
Hi,

I am trying to send an image from server to client.
The code below is the part of the server sending the image.
It looks like that everything is running smoothly but when it comes
to click on the generated new picture saved, it won't open
and this message shows:
"Error interpreting JPEG image file (Not a JPEG file: starts with 0x00 0x00)"

So I wanted to ask if there is an error in my code when it comes to sending the image or if I made a mistake elsewhere.

In other words, is this the right way of sending an image in c++ ?

1
2
3
4
5
ifstream pic_file("x.cpp");
int n= 1024;
char buffer_pics[n];
read_size=fread(buffer_pics,1,sizeof(buffer_pics), pic_file);
send(socket, (void *)&n, sizeof(n), 0);
Last edited on
Does that code send the whole thing, or just the the number 1024 in an int?
> read_size=fread(buffer_pics,1,sizeof(buffer_pics), pic_file);
If you're going to use fread() to read the file, then you need to use fopen() to open the file.
Not this -> ifstream pic_file("x.cpp");

And if it's an image file, why are you sending a .cpp file anyway?

FILE *pic_file = fopen("myimage.jpg", "rb");
Where "r" means you're opening the file to read it, and "b" means you want to read it as a binary file.

> send(socket, (void *)&n, sizeof(n), 0);
You sent n (aka 1024).
You didn't send an image - the one that might be in buffer_pics

I understand what you are saying, but is still not clear how to actually send a picture, since according to what you are saying, my code doesn't do that.
I have tried fopen before but the code generated another error when it comes to obtaining the picture size in bytes, so now I need to know how to obtain that after opening the file the way you suggested.
You can work with the language on this. You don't need to know the size of the file in order to read it; you just need it to be read in until there is no more data to read. You don't care about the size of the file; let C++ handle the details for you.

1
2
std::ifstream stream("myimage.jpg", std::ios::in | std::ios::binary);
std::vector<char> imageDataVec((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());

This creates a vector of char, named imageDataVec, that holds all the data from the file. This sample code shows this technique being used to make an exact copy of a binary file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <vector>
#include <fstream>

using namespace std;

int main()
{
        // Create an input file stream, feeding it the file of interest
	std::ifstream stream("C:/someBinaryFile.exe", std::ios::in | std::ios::binary);

       // Create a vector, telling it to populate with all the data from the input file stream
	std::vector<char> imageDataVec((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());

        // Create out file stream to new file, and (a bit laboriously) send all the data to it
	std::ofstream outStream("C:/copyFile", std::ios::binary);
	for (auto outval : imageDataVec)
	{
		outStream << outval;
	}
	std::cout << "Size: " << imageDataVec.size() << " bytes";
}


Instead of making a copy, though, you can simply send it using the function you've already picked out; you need a void pointer to the start of the data static_cast<void*>(&(imageDataVec[0])) , and the number of bytes imageDataVec.size() (since one char is of size one byte in C++).

Something like this should do it:
send (socket, static_cast<void*>(&(imageDataVec[0])), imageDataVec.size(), 0);


Last edited on
@repeater,

thank you for your help. However, as I wanted to preserve as much as possible of my code, would it be possible to just tell me where is wrong and how to change it? I just need to know the right command to send the actual picture, since what i wrote above is not working.
In addition, I would like to open the image the same way Salem suggested above:
FILE *pic_file = fopen("myimage.jpg", "rb");

Do you think is possible to incorporate this line in my code and slightly modify it in order to send the image ?

I would also like to print the size of the image, so I can send it to the client, this way once it has to receive, I can write the exact bytes to be received.
Last edited on
Okey dokey, preserve as much of this as possible:
1
2
3
4
5
ifstream pic_file("x.cpp");
int n= 1024;
char buffer_pics[n];
read_size=fread(buffer_pics,1,sizeof(buffer_pics), pic_file);
send(socket, (void *)&n, sizeof(n), 0);

and also have this:
FILE *pic_file = fopen("myimage.jpg", "rb");


Well, you need the size of the file in bytes so you can create a char array of suitable size:
auto fileSize = std::filesystem::file_size(filesystem::path("C:/Some/path/myimage.jpg"));

If you insist on a C style array, you'll need an array of the right size, and since in C++ this char buffer_pics[n]; is illegal (because in C++ you must tell the compiler the exact size of any array that is to go on the stack), you'll have to create it dynamically, so something like this:
auto array = std::make_unique<unsigned char[]>(fileSize );

Ends up something like this:

1
2
3
4
5
6
7
8
FILE *pic_file = fopen("C:/copyFile", "rb"); // create C style file stream
auto fileSize = filesystem::file_size(filesystem::path("C:/copyFile")); // get filesize using C++ filesystem library (C++17)
auto array = std::make_unique<unsigned char[]>(fileSize); // create safe dynamic array
fread(static_cast<void*>(array.get()), 1, fileSize, pic_file); // read C style stream into dynamic array
send(socket, (void *)array.get(), fileSize,  0); // pass pointer to start of dynamic array, and number of bytes, to send function

// I would also like to print the size of the image
cout << fileSize;



I would be remiss if I didn't say that this is an unholy mashup of C++ and C. You've got what you asked for, with as much of your original C code as can be salvaged, but if you're going to use C++, you should consider just using C++.

Last edited on
@repeater

I followed your initial advice and used c++ lines to send the image, however, I am now having the same problem as before.
The code runs smoothly but the file transferred is not an image, infact the generated file keeps showing this message ""Error interpreting JPEG image file (Not a JPEG file: starts with 0x00 0x00)"
instead of the actual picture.
Perhaps the code that you are using to receive and write the data isn't correct.

The example code above in which I copy the file produces an exact copy, so the read of data from file into the vector is correct. So lets see your send line, and the code at the other end receiving the data.
Last edited on
here is how I implemented the code:

1
2
3
4
5
6
char file_name[] ={"pics.jpeg"};
ifstream stream(file_name, std::ios::in | std::ios::binary);
vector<char> imageDataVec((istreambuf_iterator<char>(stream)), istreambuf_iterator<char>());
cout << "Size: " << imageDataVec.size() << " bytes";
 
send(socket, static_cast<void*>(&(imageDataVec[0])), imageDataVec.size(), 0);


If you want I can post the receiver too, but is in python, so I m not sure how is that gonna work out.
However, i doubt that the receiver is wrong since the lines are just a couple.
Is the size reported the expected file size?

What do you get when you put this on the front of the send line:
auto bytes_sent =
and this after it:
cout << "Bytes sent = " << bytes_sent << '\n';
Last edited on
I have been trying to send first of all the integer corresponding to the size of the picture, and then the picture itself.
Here is the catch: when I sent either/or, I have no problems, but when I send them both, the picture generated presents the same error.
How do I send them both without running in such errors?

N.B. for each send, there is a recv on the other side

1
2
3
4
5
long converted_number = htonl(imageDataVec.size()); \\these two lines are sending the size of the picture
send(new_socket, &converted_number, sizeof(converted_number), 0);\\but once implemented, the generated \\picture is faulty
 

send(new_socket, static_cast<void*>(&(imageDataVec[0])), imageDataVec.size(), 0); \\this sends the picture, this alone, without the two lines above, generates the picture normally
> i doubt that the receiver is wrong since the lines are just a couple.
¿did you write them?


maybe if you stop lying you'll receive better help.
You have to check the return code from send(). It's normal for send() not send a large buffer at once. You need to use a loop.
1
2
3
4
5
6
7
8
9
size_t sent{};
while (sent < imageDataVec.size()) {
    int nbytes = send(socket, &imageDataVec[sent], imageDataVec.size() - sent, 0);
    if (nbytes <= 0) {
        std::clog << "error: while sending image\n";
        break;
    }
    sent += nbytes;
}


Although that one liner to read the buffer is kinda elegant, it's faster to read/send chunks in, say, 64k chunks because of i/o speeds vs. cpu speeds, read ahead on the device and so on.

It's also faster to do an unbuffered read because you're reading and discarding the content. And that means using open/read/close (or OpenFile/ReadFile/CloseHandle) rather than using a std::ifstream. And that's particularly true when using slow file systems like variants of FAT, NTFS or ZFS.
Last edited on
@ne5@ne555:
as I wrote above, my receiver is in python, and this is a c++ forum, therefore I will only post them if specifically asked.
Yes I did write the lines myself, and I am not sure what kind of 'logic' would make you think I have a reason to lie. If you would spend your time in actually helping people instead of venting illogical remarks out of the blue for no reason, this community including yourself, would perhaps benefit from it a lot more.

@kbw, what do you mean by "return code from send()" ?
Last edited on
what do you mean by "return code from send()"


The send function returns a value. It is common to refer to this as a "return code", especially when it can indicate success or failure.

Currently, your code ignores this value; if you stored this value, and then output it, you would be able to see how much data the send function thinks it sent.

In this call to send, the return code is stored in the variable nbytes

int nbytes = send(socket, &imageDataVec[sent], imageDataVec.size() - sent, 0);

Last edited on
thank you @repeater


However, implementing the lines posted by kbw didn't change the outcome at all.
I still obtain a generated picture with the same error.
Also, printing nbytes gives me the same exact number as imageDataVec.size(),
which I assume is correct.
Last edited on
> I am not sure what kind of 'logic' would make you think I have a reason to lie.
your first post didn't compile but you were complaining about a logic error
your image filename was x.cpp
and you went and sent another completely unrelated variable

¿did you even read your own code?


- test a `copy' program: read the file, write to disk
- send "plain text", so you know what you are receiving
- rtfm

> when I sent either/or, I have no problems, but when I send them both, the
> picture generated presents the same error.
¿did you receiver expect two things?
¿why do you want so much to send the size if sending just the picture works?
so sending the picture works, ¿what are we doing then?
just because I (mistakenly, as is supposed to be a pic) use the file names I read somewhere else, that does not mean that I "copy" someone else's work. When I'm here, I use different names for files, so what?

¿did you even read your own code?

That's another rude comment. I do ask for help/suggestions here and implement it in my own code, so of course I read it. Is embarrassing that I just have to answer such a silly question.

¿did you receiver expect two things?

yes it does. For each 'send' command there is a 'receive' one on the other side.

¿why do you want so much to send the size if sending just the picture works?

so much? As I already mentioned, the first messsage is supposed to send the size (int) of the image I wanna send, so the receiver on the other side can use that same integer as a parameter to receive the picture. An integer and a picture is not "much" like you are claiming.

so sending the picture works, ¿what are we doing then?

Sending picture works only if on the other side I manually write the picture size in the receive command as a parameter. But what I wanna do is to send the parameter first via socket, so the receiver can use directly that.


With this being said: beware that I don't have as much programming experience as most of you here, that is why I ask what I ask. Therefore if you have the potential and the willingness to give me some constructive guidance, I'll be more than happy to consider your suggestions or answer any clarifications you may have due to my sometimes messy code.
But if you are here to spread insulting and condescending remarks, I would appreciate you staying away from my posts instead of coming here and displaying rudeness. That doesn't help anyone.
when asking about code, post that code
don't post another code that has different problems, it's a waste of time

show your receiver code.

try something like (pseudocode)
1
2
3
4
5
6
std::string word;
while(std::cin >> word)
   send(word); //plain text

for(int K=0; K<42; ++K)
   send(K); //a sequence of numbers 
once that works, move to sending the image.

also, ¿how are you creating the socket? (both ends)
Last edited on
Pages: 12