2

I'm doing some sfml project for school and teacher wants only the .exe program. I'm using Visual Studio 2017. In this project I'm using texture from .jpg file

sf::RenderWindow window(sf::VideoMode(640, 480, 32), "Kurs SFML ");

sf::Texture texture; 
texture.loadFromFile("wood.jpg");

sf::Sprite pic;
pic.setTexture(texture);

while (window.isOpen())
{
    sf::Event event;
    while (window.pollEvent(event))
    {
        if (event.type == sf::Event::Closed)
            window.close();

    }
    window.clear();
    window.draw(pic);
    window.display(); 

This file ( wood.jpg ) needs to be to in the same folder as project to show this texture otherwise it only shows black screen. When I checked the .exe program which is in another folder, it also needs this file to be in this folder or .exe shows black screen. But my teacher wants only .exe file without any folders. So is it possible to do something to not include this file( wood.jpg ) but show the texture in the .exe ?

db14
  • 107
  • 10
  • You might use a resource for that. – user0042 Jan 02 '18 at 17:51
  • What do You mean ? – db14 Jan 02 '18 at 17:56
  • I mean an embedded resource file. Check the VS documentation how you can access embedded resource files using a filepath. It's a special protocol. – user0042 Jan 02 '18 at 17:57
  • Write the full path of your image (ex: `texture.loadFromFile("C:\wood.png")`) then submit your .exe and add a note that image should exist in the `C:\ `drive – Khalil Khalaf Jan 02 '18 at 17:59
  • @KhalilKhalaf _"But my teacher wants only .exe file without any folders."_ I'm pretty sure their teacher doesn't want to install extra `.jpg` files either. – user0042 Jan 02 '18 at 18:09
  • My hint is similar like the one of user0042: My answer to [SO: Paint a rect on qglwidget at specifit times](https://stackoverflow.com/a/42420804/7478597) uses an image for an OpenGL texture which is embedded in the source code. The embedded image source was converted using [GIMP](https://www.gimp.org/) which is "free". – Scheff's Cat Jan 02 '18 at 18:10
  • I think it is "unclear what the teacher is asking for" and OP needs to clarify this question with his/her teacher – Khalil Khalaf Jan 02 '18 at 18:14

2 Answers2

1

Embed your texture in your executable.

One easy solution is to write a small tool that reads the file and writes out a C++ source file with a constexpr std::array containing the raw bytes. Then load your texture from that variable (SFML has functions to load a resource from memory) that you link into your executable.

Writing such a tool shouldn't be more than 10-20 lines of code.

Jesper Juhl
  • 1
  • 3
  • 38
  • 63
  • 2
    I did it (with a bit more lines than 20) in my answer to [SO: How to include data object files (images, etc.) in program and access the symbols?](https://stackoverflow.com/a/47415163/7478597). ;-) – Scheff's Cat Jan 02 '18 at 18:14
  • I checked it and it looks for me like script in linux, yes ? You give argument for file ( which is .jpg file for example) and it converts. But how should I use it, add it to project ? Sorry for stupid questions, i'm newbie :( – db14 Jan 02 '18 at 18:42
  • There's no need to write such tool yourself though, since the open source project vim already contains a tool that does this: xxd – eerorika Jan 02 '18 at 18:55
  • 1
    @db14 Sorry, for late reply. (You should've addressed me with `@Scheff` to get my attention.) The tool is written in C++. It should compile in any nearly C++11 compliant compiler (as in mine which is the pre-installed of VS2013). I made the demonstration of the tool in `bash` on cygwin as it illustrates easily how to use it. This is simple to repeat with the appropriate tools which are common/easy to get on Linux, other *x OSes, or even on cygwin/Windows. But even without this, the shell session should illustrate how things are working. – Scheff's Cat Jan 03 '18 at 15:00
  • 1
    @db14 The tool writes a piece of C source code (which can `#include`d in C or C++ sources). In the demo session, I wrote a sample program which includes the generated source file and writes the encoded data back to a new file. (I used `cat` for writing this sample program for demonstration. Normally, I use VS2013 or Notepad++.) Afterwards, it is compiled and executed. This shall show (by using `diff`) that the output of data compiled from the generated source file is fully identical to the original file. – Scheff's Cat Jan 03 '18 at 15:05
  • 1
    @db14 If the image does not change, it is fine to run it once e.g. in `cmd.exe` and copy the output file to the appropriate folder where your C++ sources are in. The call on `cmd.exe` should actually look exactly like in `bash`: `binToC fluffy_cat.png > fluffy_cat.inc`. The output is done to standard output - hence the re-direction into file (`> fluffy_cat.inc`). The suffix `.inc` has been used because this is an include file but not like a header (as it contains initialization and may be included in one source only - otherwise you get linker trouble). – Scheff's Cat Jan 03 '18 at 15:20
  • 1
    @db14 On our side, such tools are even part of our "build chain" in VS2013. In the past, (when we were still on VS2008), I was able to build such projects manually but meanwhile we use CMake for this. So, yes it's possible to automate binary-to-source-conversion in VS2013 (or other IDEs probably as well) but, no, I cannot explain exactly how to prepare this properly. (Had to dig in a project example or to google in case.) – Scheff's Cat Jan 03 '18 at 15:24
  • Thanks very much :) I will try it out. – db14 Jan 03 '18 at 16:38
1

For a SFML specific solution you can do this.

sf::Image tmp;
tmp.loadFromFile("super.jpeg");

std::ofstream file;
file.open("textarray.cpp");
size_t psize = tmp.getSize().x * tmp.getSize().y * 4;
auto ptr = tmp.getPixelsPtr();

file << "sf::Uint8 imageArray[] = {" << (int)ptr[0];
for (size_t i = 1; i<psize; ++i)
    file << "," << (int)ptr[i];
file << "};";

file.close();

This will create a file name textarray.cpp containing something that looks like sf::Uint8 imageArray[] = {...};

Then you can load it in your program like this.

sf::Uint8 imageArray[] = {...};
sf::Image img;
img.create(80, 80, imageArray); // Replace 80, 80 with width and height of your image!!!
sf::Texture texture;
texture.loadFromImage(img);
sf::Sprite sprite;
sprite.setTexture(texture);

From here, just draw the sprite like normal.

super
  • 9,722
  • 2
  • 13
  • 25
  • I tried it, but imageArray[] is so long that i can't even compile it. Like it was lagging when i copied it from this file and now in visual studio it's compiling for like 10 minutes :/ – db14 Jan 02 '18 at 23:05
  • 1
    @db14 "I tried it, but imageArray[] is so long that i can't even compile it." It seems, you have a real large image. Would it hurt to scale it down a bit? Another option would be to split the whole binary data into separate chunks and make an array of pointers with addresses of these chunks, or put a "next pointer" into the chunk `struct` so that they can form a list. (I remember roughly that VS has a limit of 64KB concerning variable initializers.) – Scheff's Cat Jan 03 '18 at 05:34
  • One way to get around having to copy the string is to make a `textarray.h` file and define a `extern sf::Uint8 imageArray[]` in it. Then `#include "textarray.h"` in your main.cpp. This will however not help with the compile time. I would go with scaling down the image and then `sprite.scale` it back up to compensate. – super Jan 03 '18 at 09:33
  • This picture is pretty small - 600x585 in pixels. The weight of it is 168 KB and the file with imageArray is about 5 Mb. Do You think that scaling it down can help ? – db14 Jan 03 '18 at 11:54
  • I tried it with a 80x80 picture. Scaling it down will help, but question is how much you need to do so. If Scheff is right about VS having a limit on variable initialization that might be the issue. – super Jan 03 '18 at 12:30
  • You could technically do this exact same thing by putting the binary image data (168kb in your case) into an array and loading it with texture.loadFromMemory. This might work better for you if you can figure out how to put the binary image data into a hard coded array. – super Jan 03 '18 at 12:33