raytracing.github.io icon indicating copy to clipboard operation
raytracing.github.io copied to clipboard

Can't open created ppm file (PPM must be ASCII or UTF-8)

Open drieslamberechts opened this issue 4 years ago • 20 comments

I've just started reading/implementing Ray Tracing in One Weekend and already stumbled upon this problem. This is my c++ code:

int main() {
  const int image_width = 256;
  const int image_height = 256;

  std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";

  for (int y = image_height-1; y >= 0; --y) {
    std::cerr << "\rScanlines remaining: " << y << ' ' << std::flush;
    for (int x = 0; x < image_width; ++x) {
      auto r = double(x) / (image_width-1);
      auto g = double(y) / (image_height-1);
      auto b = 0.25;

      int ir = static_cast<int>(255.999 * r);
      int ig = static_cast<int>(255.999 * g);
      int ib = static_cast<int>(255.999 * b);

      std::cout << ir << ' ' << ig << ' ' << ib << '\n';
    }
  }
}

And this is the output in the .ppm file:

P3 256 256 255 0 255 63 1 255 63 2 255 63 3 255 63 4 255 63 5 255 63 6 255 63 7 255 63 8 255 63 9 255 63 10 255 63 ...

Tried opening this with Gimp, XNView and IrfanView but they all can't seem to read the file.

drieslamberechts avatar Jun 10 '20 11:06 drieslamberechts

From the book:

Opening the output file (in ToyViewer on my Mac, but try it in your favorite viewer and Google “ppm viewer” if your viewer doesn’t support it) ...

I use ImageMagick personally, but there are other results.

hollasch avatar Jun 10 '20 18:06 hollasch

I'm on Windows by the way... I installed ImageMagick and still get this error: "Improper image header".

I've searched for information about the ppm header and I don't see any differences compared to mine so I'm not sure what's happening.

drieslamberechts avatar Jun 11 '20 06:06 drieslamberechts

x.txt

Attached a PPM file that you should be able to view. You'll need to rename the extension from .txt to .ppm (GitHub restricts uploads to a small set of acceptable file extensions).

Is your file written out with a Unicode BOM perhaps? Here are the first bytes of the attached PPM file:

50330d0a 32302031 310d0a32 35350d0a  # 00000000  P3..20 11..255..
32323020 32333520 3235350d 0a323230  # 00000010  220 235 255..220
20323335 20323535 0d0a3232 30203233  # 00000020   235 255..220 23
35203235 350d0a32 32302032 33352032  # 00000030  5 255..220 235 2
35350d0a 32323020 32333520 3235350d  # 00000040  55..220 235 255.
0a323230 20323335 20323535 0d0a3232  # 00000050  .220 235 255..22
30203233 35203235 350d0a32 32302032  # 00000060  0 235 255..220 2
33352032 35350d0a 32323020 32333520  # 00000070  35 255..220 235
3235350d 0a323230 20323335 20323535  # 00000080  255..220 235 255
0d0a3232 30203233 35203235 350d0a32  # 00000090  ..220 235 255..2

(Note that you should be able to use either LF or CRLF line endings.)

hollasch avatar Jun 11 '20 06:06 hollasch

I reran your code, on windows, and got a ppm that I was able to view in FastStone

trevordblack avatar Jun 11 '20 07:06 trevordblack

You could also rename your PPM output file to have a .txt extension, and upload it here so we can try it out on our end.

hollasch avatar Jun 11 '20 07:06 hollasch

@hollasch Thanks! The file you sent does work on my end.

I attached my generated .ppm

Maybe some more needed information: I built my .exe with Visual Studio 2019 with no special settings.

image.txt

drieslamberechts avatar Jun 11 '20 07:06 drieslamberechts

Yup. Your file is UTF-16 with BOM. It should be UTF-8 or ASCII with no BOM.

hollasch avatar Jun 11 '20 07:06 hollasch

Image looks good when converted to UTF-8 no BOM.

hollasch avatar Jun 11 '20 07:06 hollasch

Ok great! So I assume this has something to do with the Visual Studio project settings? I'm going to search on how to set the output format.

drieslamberechts avatar Jun 11 '20 07:06 drieslamberechts

Ugh. Now I'm not confident that I know how my code's working. :)

I thought it would be a project setting, but then I just read that the text output is indeed UTF-8, but the Windows console transforms this to UTF-16. I remember getting this same result in another project, and ended up (for a while) setting my codepage to Unicode to fix this.

You can change the codepage in a Windows command shell with the chcp command. By default it's 437; Unicode is 65001. As an experiment, run the command chcp 65001, and then try re-running your program and redirecting the output into your x.ppm output file, then see if that is readable (is UTF-8 no-bom).

There's also mention of the Windows API SetConsoleOutputCP(CP_UTF8); (include windows.h) to do this programatically.

Still I don't know why this is all working for me, as I'm doing none of these things. It's possible that CMake is fixing this for me, by supplying the Visual Studio /utf8 compiler option.

hollasch avatar Jun 11 '20 07:06 hollasch

I don't see any obvious Unicode or UTF-8 mentions in the CMake-generated .vcxproj files.

hollasch avatar Jun 11 '20 07:06 hollasch

Ok, I tried it but it wasn't working. This gave me an idea however. I was running the executable from a PowerShell window inside Visual Studio. I tried running it from a regular CMD window and that fixed the issue.

drieslamberechts avatar Jun 11 '20 07:06 drieslamberechts

Sigh.

hollasch avatar Jun 11 '20 07:06 hollasch

Without too much work, you could alter the program to take an output image filename on the command line and create the file directly. Or just take your workaround and carry on.

hollasch avatar Jun 11 '20 07:06 hollasch

However, it's useful to note that the program/build wasn't the issue, it was the environment inducing the encoding change.

hollasch avatar Jun 11 '20 08:06 hollasch

I can open a CMD window inside VS so it's not really an issue at the moment. And yes, I assumed it was going to be something like that. This might be good to add as a note in the book. Anyway, @hollasch, thank you very much for helping me out! :)

drieslamberechts avatar Jun 11 '20 08:06 drieslamberechts

Glad to help. We have kicked around the idea of general system-specific notes. This would indeed be a good candidate entry. I'm leaving this open, assigned to a future milestone.

hollasch avatar Jun 11 '20 08:06 hollasch

Same problem, thanks for helping me track this down. This is what fixed it for me with Powershell on Windows. Based on some stack overflow posts this is a problem lots of people have with Powershell for various text outputs:

PS: C:\raytracing\main\Release> main.exe | set-content image.ppm -encoding String

I tried -encoding UTF8 and -encoding Unicode but those didn't work.

rdthree avatar Dec 06 '20 23:12 rdthree

Maybe this should get spun out into a discussion? I'm not sure what the issue to solve here is?

trevordblack avatar Jan 10 '21 22:01 trevordblack

Since this is such a basic requirement for our project, it warrants a quick mention somehow. In the past, we talked about developer notes for various platforms, but for now we can just mention generally that if you can't see the image, you should check the actual emitted bytes somehow, since all of the rest depends on being able to view the resulting images.

hollasch avatar Jan 11 '21 02:01 hollasch

Revisiting this, I like Trevor's suggestion. I'll seed a discussion, and then point to it from a very short comment in the book.

hollasch avatar May 10 '23 18:05 hollasch

See discussion #1114.

hollasch avatar May 10 '23 19:05 hollasch