LodePNG error

Hi, I want to create a png file using raw pixel data using LodePNG.
However the sample will not compile. Gives tons or errors that don't make sense.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  // PNG.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

//#include <iostream>
/*
LodePNG Examples

Copyright (c) 2005-2012 Lode Vandevenne

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

    1. The origin of this software must not be misrepresented; you must not
    claim that you wrote the original software. If you use this software
    in a product, an acknowledgment in the product documentation would be
    appreciated but is not required.

    2. Altered source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

    3. This notice may not be removed or altered from any source
    distribution.
*/

#include "C:\Users\Chris\Desktop\PNG\lodepng.h"
#include <iostream>





/*
3 ways to encode a PNG from RGBA pixel data to a file (and 2 in-memory ways).
NOTE: these samples overwrite the file or test.png without warning!
*/

//g++ lodepng.cpp examples/example_encode.cpp -I./ -ansi -pedantic -Wall -Wextra -O3

//Example 1
//Encode from raw pixels to disk with a single function call
//The image argument has width * height RGBA pixels or width * height * 4 bytes
void encodeOneStep(const char* filename, std::vector<unsigned char>& image, unsigned width, unsigned height) {
    //Encode the image
    unsigned error = lodepng::encode(filename, image, width, height);

    //if there's an error, display it
    if (error) std::cout << "encoder error " << error << ": " << lodepng_error_text(error) << std::endl;
}

//Example 2
//Encode from raw pixels to an in-memory PNG file first, then write it to disk
//The image argument has width * height RGBA pixels or width * height * 4 bytes
void encodeTwoSteps(const char* filename, std::vector<unsigned char>& image, unsigned width, unsigned height) {
    std::vector<unsigned char> png;

    unsigned error = lodepng::encode(png, image, width, height);
    if (!error) lodepng::save_file(png, filename);

    //if there's an error, display it
    if (error) std::cout << "encoder error " << error << ": " << lodepng_error_text(error) << std::endl;
}

//Example 3
//Save a PNG file to disk using a State, normally needed for more advanced usage.
//The image argument has width * height RGBA pixels or width * height * 4 bytes
void encodeWithState(const char* filename, std::vector<unsigned char>& image, unsigned width, unsigned height) {
    std::vector<unsigned char> png;
    lodepng::State state; //optionally customize this one

    unsigned error = lodepng::encode(png, image, width, height, state);
    if (!error) lodepng::save_file(png, filename);

    //if there's an error, display it
    if (error) std::cout << "encoder error " << error << ": " << lodepng_error_text(error) << std::endl;
}

//saves image to filename given as argument. Warning, this overwrites the file without warning!
int main(int argc, char* argv[]) {
    //NOTE: this sample will overwrite the file or test.png without warning!
    const char* filename = argc > 1 ? argv[1] : "test.png";

    //generate some image
    unsigned width = 512, height = 512;
    std::vector<unsigned char> image;
    image.resize(width * height * 4);
    for (unsigned y = 0; y < height; y++)
        for (unsigned x = 0; x < width; x++) {
            image[4 * width * y + 4 * x + 0] = 255 * !(x & y);
            image[4 * width * y + 4 * x + 1] = x ^ y;
            image[4 * width * y + 4 * x + 2] = x | y;
            image[4 * width * y + 4 * x + 3] = 255;
        }

    encodeOneStep(filename, image, width, height);
}




The error
1
2
3
4
5
6
7
8
9
10
11
Build started...
1
1>PNG.cpp
1>PNG.obj : error LNK2019: unresolved external symbol "unsigned int __cdecl lodepng::encode(class std::vector<unsigned char,class std::allocator<unsigned char> > &,class std::vector<unsigned char,class std::allocator<unsigned char> > const &,unsigned int,unsigned int,enum LodePNGColorType,unsigned int)" (?encode@lodepng@@YAIAAV?$vector@EV?$allocator@E@std@@@std@@ABV23@IIW4LodePNGColorType@@I@Z) referenced in function "void __cdecl encodeTwoSteps(char const *,class std::vector<unsigned char,class std::allocator<unsigned char> > &,unsigned int,unsigned int)" (?encodeTwoSteps@@YAXPBDAAV?$vector@EV?$allocator@E@std@@@std@@II@Z)
1>PNG.obj : error LNK2019: unresolved external symbol "unsigned int __cdecl lodepng::encode(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class std::vector<unsigned char,class std::allocator<unsigned char> > const &,unsigned int,unsigned int,enum LodePNGColorType,unsigned int)" (?encode@lodepng@@YAIABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABV?$vector@EV?$allocator@E@std@@@3@IIW4LodePNGColorType@@I@Z) referenced in function "void __cdecl encodeOneStep(char const *,class std::vector<unsigned char,class std::allocator<unsigned char> > &,unsigned int,unsigned int)" (?encodeOneStep@@YAXPBDAAV?$vector@EV?$allocator@E@std@@@std@@II@Z)
1>PNG.obj : error LNK2019: unresolved external symbol "char const * __cdecl lodepng_error_text(unsigned int)" (?lodepng_error_text@@YAPBDI@Z) referenced in function "void __cdecl encodeOneStep(char const *,class std::vector<unsigned char,class std::allocator<unsigned char> > &,unsigned int,unsigned int)" (?encodeOneStep@@YAXPBDAAV?$vector@EV?$allocator@E@std@@@std@@II@Z)
1>PNG.obj : error LNK2019: unresolved external symbol "public: __thiscall lodepng::State::State(void)" (??0State@lodepng@@QAE@XZ) referenced in function "void __cdecl encodeWithState(char const *,class std::vector<unsigned char,class std::allocator<unsigned char> > &,unsigned int,unsigned int)" (?encodeWithState@@YAXPBDAAV?$vector@EV?$allocator@E@std@@@std@@II@Z)
1>PNG.obj : error LNK2019: unresolved external symbol "public: __thiscall lodepng::State::~State(void)" (??1State@lodepng@@QAE@XZ) referenced in function "void __cdecl encodeWithState(char const *,class std::vector<unsigned char,class std::allocator<unsigned char> > &,unsigned int,unsigned int)" (?encodeWithState@@YAXPBDAAV?$vector@EV?$allocator@E@std@@@std@@II@Z)
1>PNG.obj : error LNK2019: unresolved external symbol "unsigned int __cdecl lodepng::encode(class std::vector<unsigned char,class std::allocator<unsigned char> > &,class std::vector<unsigned char,class std::allocator<unsigned char> > const &,unsigned int,unsigned int,class lodepng::State &)" (?encode@lodepng@@YAIAAV?$vector@EV?$allocator@E@std@@@std@@ABV23@IIAAVState@1@@Z) referenced in function "void __cdecl encodeWithState(char const *,class std::vector<unsigned char,class std::allocator<unsigned char> > &,unsigned int,unsigned int)" (?encodeWithState@@YAXPBDAAV?$vector@EV?$allocator@E@std@@@std@@II@Z)
1>PNG.obj : error LNK2019: unresolved external symbol "unsigned int __cdecl lodepng::save_file(class std::vector<unsigned char,class std::allocator<unsigned char> > const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?save_file@lodepng@@YAIABV?$vector@EV?$allocator@E@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@3@@Z) referenced in function "void __cdecl encodeTwoSteps(char const *,class std::vector<unsigned char,class std::allocator<unsigned char> > &,unsigned int,unsigned int)" (?encodeTwoSteps@@YAXPBDAAV?$vector@EV?$allocator@E@std@@@std@@II@Z)
1>C:\Users\Chris\source\repos\PNG\Debug\PNG.exe : fatal error LNK1120: 7 unresolved externals
1>Done building project "PNG.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


> //g++ lodepng.cpp examples/example_encode.cpp -I./ -ansi -pedantic -Wall -Wextra -O3
It tells you here what you need to do to compile it.
There are TWO source files.

But as you're using a VS project, you add lodepng.cpp as a source file.

> #include "C:\Users\Chris\Desktop\PNG\lodepng.h"
You'd be better copying it (and lodepng.cpp) to your C:\Users\Chris\source\repos\PNG directory.
Having absolute include paths is extremely fragile.

> error LNK2019: unresolved external symbol
When you see this, one of three things is the likely mistake
- There is a typo in the symbol name (check spelling and capitalisation)
- You're missing a source file in your project
- You're missing an external library.
Thanks, it now compiles and generates the sample png image.

I am struggling with the below code though.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//saves image to filename given as argument. Warning, this overwrites the file without warning!
int main(int argc, char* argv[]) {
    //NOTE: this sample will overwrite the file or test.png without warning!
    const char* filename = argc > 1 ? argv[1] : "test.png";

    //generate some image
    unsigned width = 512, height = 512;
    std::vector<unsigned char> image;
    image.resize(width * height * 4);
    for (unsigned y = 0; y < height; y++)
        for (unsigned x = 0; x < width; x++) {
            image[4 * width * y + 4 * x + 0] = 255 * !(x & y);
            image[4 * width * y + 4 * x + 1] = x ^ y;
            image[4 * width * y + 4 * x + 2] = x | y;
            image[4 * width * y + 4 * x + 3] = 255;
        }

    encodeOneStep(filename, image, width, height);
}


I need to write individual pixels. How do I for example create a red gradient. From Red to White? I spent the last few hours playing with the code but I still don't understand it.

Thanks for your patience.



Ok I got the the gradient working. But its very pixalated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//saves image to filename given as argument. Warning, this overwrites the file without warning!
int main(int argc, char* argv[]) {
    //NOTE: this sample will overwrite the file or test.png without warning!
    const char* filename = argc > 1 ? argv[1] : "test.png";

    //generate some image
    unsigned width = 512, height = 512;
    std::vector<unsigned char> image;
    image.resize(width * height * 8);
    int y = 0;
    for (unsigned x = 0; x < (512*512); x++)
    {
        image[4 * (width)*y + 8 * x + 0] = x;
        image[4 * x + 1] = 0;
        image[4 * x + 2] = 0;
        image[4 * width * y + 4 * x + 3] = 255;
    }
        

    encodeOneStep(filename, image, width, height);
}



Here is a solid red colour but again its very pixalated. looks like its made up of a bunch of vertical lines.... It needs to be pixel perfect...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//saves image to filename given as argument. Warning, this overwrites the file without warning!
int main(int argc, char* argv[]) {
    //NOTE: this sample will overwrite the file or test.png without warning!
    const char* filename = argc > 1 ? argv[1] : "test.png";

    //generate some image
    unsigned width = 512, height = 512;
    std::vector<unsigned char> image;
    image.resize(width * height * 8);
    int y = 0;
    for (unsigned x = 0; x < (512*512); x++)
    {
        image[4 * (width)*y + 8 * x + 0] = 255;
        image[4 * x + 1] = 0;
        image[4 * x + 2] = 0;
        image[4 * width * y + 4 * x + 3] = 255;
    }
        

    encodeOneStep(filename, image, width, height);
}

+ 0 is red, +1 is green, +2 is blue and +3 is alpha (the opacity of a colour). These numbers vary from 0 to 255 where 255 is full. So red would 255, 0, 0, 255 and white would be 0, 0, 0, 255
You're using y in the for loop, but y is always 0... Why not use the 2 for loops as in the given example.

PS L9 - why *8 and not *4?
Last edited on
Yes I know that much. Here is the example output. If you zoom in you will see vertical lines. Red then black then red etc.

https://imgur.com/a/KiS9TsB
What about (not tried):

1
2
3
4
5
6
7
8
9
10
const unsigned width = 512, height = 512, no_elems = width * height * 4;

	std::vector<unsigned char> image(no_elems);

	for (unsigned x = 0; x < no_elems; x += 4) {
		image[x + 0] = 255;
		image[x + 1] = 0;
		image[x + 2] = 0;
		image[x + 3] = 255;
	}


Have you tried changing the value at x + 3 ?
Last edited on
> image[4 * (width)*y + 8 * x + 0]
This is too complicated to know whether it's right or wrong.

You don't have to cram everything into a single expression.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    //generate some image
    unsigned width = 512, height = 512;
    const unsigned bytes_per_pixel = 4;
    std::vector<unsigned char> image;
    image.resize(width * height * bytes_per_pixel);
    for ( unsigned h = 0 ; h < height ; h++ ) {
        for ( unsigned w = 0 ; w < width ; w++ ) {
            unsigned index = h * width + w;
            unsigned pixel = index * bytes_per_pixel;
            image[pixel+0] = 255;  // red
            image[pixel+1] = 0;    // green
            image[pixel+2] = 0;    // blue
            image[pixel+3] = 255;  // alpha
        }
    }
Thanks. Starting to make a little more sense now. I got the single colour working but when I try to do the gradient it shows two tiles. see screenshot.
https://imgur.com/a/OVSSTxt

I know i'm slow. I try.

1
2
3
4
5
6
7
8
9
10
11
12
 const unsigned width = 512, height = 512, no_elems = width * height * 4;

    std::vector<unsigned char> image(no_elems);
    int y = 0;
    for (unsigned x = 0; x < no_elems; x += 4,y++) {
        image[x + 0] = y;
        image[x + 1] = 0;
        image[x + 2] = 0;
        image[x + 3] = 255;
    }

    encodeOneStep(filename, image, width, height);
I think I got it working. Thanks for the help!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 //generate some image
    unsigned width = 512, height = 512;
    const unsigned bytes_per_pixel = 4;
    std::vector<unsigned char> image;
    image.resize(width * height * bytes_per_pixel);
    for (unsigned h = 0; h < height; h++) {
        for (unsigned w = 0; w < width; w++) {
            unsigned index = h * width + w;
            unsigned pixel = index * bytes_per_pixel;
            image[pixel + 0] = h/2;  // red
            image[pixel + 1] = 0;    // green
            image[pixel + 2] = 0;    // blue
            image[pixel + 3] = 255;  // alpha
        }
    }
OK. here is some code I would like to convert to the .png image format. The first block of code is a function that writes to the .bmp format. It loads image data from a file then exports it to a .bmp file. It works fine. Now I want to do the same thing with a .png.

I hope you guys don't mind. The code was too long to post so I hosted it on mediafire.

https://www.mediafire.com/file/9zq9tplcizbuu88/source.zip/file
OK. this is as close as I got it. However it is upside down and mirrored...
Any ideas how to change that?

check the code here.
https://www.mediafire.com/file/8brpdq6csqoxwin/PNG_ALMOST_WORKING_BUT_UP_SIDE_DOWN_MIRRORED.txt/file

Thanks.
Not sure about the mirroring, but upside down is easily explained by the fact that BMP considers 0,0 to be the bottom-left corner, whereas most everything else considers 0,0 to be the top-left corner.
I am trying to reverse the vector to hopefully rotate the image. It compiles but it exports a black image...
Here is part of the code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Encode from raw pixels to disk with a single function call
//The image argument has width * height RGBA pixels or width * height * 4 bytes
void encodeOneStep(const char* filename, std::vector<unsigned char>& image, unsigned width, unsigned height) {
    //Encode the image
    unsigned error = lodepng::encode(filename, image, width, height);

    //if there's an error, display it
    if (error) std::cout << "encoder error " << error << ": " << lodepng_error_text(error) << std::endl;
}

int main(int argc, char* argv[])
{
    const unsigned width = 16, height = 16, no_elems = 4088;
    std::vector<unsigned char> image(no_elems);



// set some values:
            for (int i = 1; i <= 4088; ++i) image.push_back(image[i]);   // 1 2 3 4 5 6 7 8 9

            std::reverse(image.begin(), image.end());    // 9 8 7 6 5 4 3 2 1






            encodeOneStep(filename, image, width, height);
If 'image' has 4088 elements, then image[4088] is out of range, and invokes undefined behavior (line 19).
<edit: Didn't notice the push_back. DizzyDon is correct.>

Start your indices at 0, not 1.

Also, don't put magic numbers in code (line 13 vs. line 19).

std::reverse(image.begin(), image.end()); is NOT going to do what you want.
Suppose your image was 1x1 pixel, [0 255 0 255] (full-opacity green).
If you reverse this, you get [255 0 255 0] (0-opacity magenta).

I would consider defining a consistent coordinate system such that you don't need to transform the image at the end, but if you do need to, you need to swap each individual row of the image.

Also, rotate? What exactly is the issue here? I assume you need to reverse your y-coordinate (mirror across x-axis).
i.e.

     ^       becomes   x     .
   x   .                  v      


for y = 0 to height/2,
    for x = 0 to width
        swap(image[y, x], image[height-1 - y, x])


That's the usual case. If you need to rotate the image, that's going to be a different transformation.
Last edited on
The image is black for two reasons.
Firstly, you construct it as a certain size intialized to zeros.
Then by using push_back you are pushing entirely new elements after the pre-existing elements, extending the size of the image vector.
Also, you are assigning image[i], which would be zero, to the new element.
So it should be more like this if you mean to assign 0 to element 0, 1 to element 1, etc.

 
for (int i = 0; i < 4088; ++i) image[i] = i;

Last edited on
Thanks for the tips. I got the image to show up correctly now. Turns out the tile data was not in the right order.
Topic archived. No new replies allowed.