Image pixel to vector

Is there any way to read various images from different types like bmp, jpeg, png and put those pixels values in a C++ vector, then modify those pixels values and save the image pixel by changing to a different location within the directory or some database? I am trying to see if there is a way to do this without using any third party lib functions.
Without using a third-party library, you will have to decode the image data (pixel values) from the "binary" file yourself! This is like re-inventing the wheel. It may be relatively easy with Bitmap files, which are just a small header followed by "raw" pixel data. But it will be a huge project for compressed formats like JPEG or PNG.

Better go with one of the existing and well-tested image libraries:
* http://libjpeg.sourceforge.net/
* http://www.libpng.org/pub/png/libpng.html

Or use a library like DevIL that supports many different image file formats all at once:
http://openil.sourceforge.net/about.php

If you are working with a framework, such as Qt, the framework usually provides a generic "Image" class that already supports the most common image file formats "out-of-the-box". For example:
https://het.as.utexas.edu/HET/Software/html/qimage.html

If you really want to write code to decode JPEG yourself, here is a basic explanation on how JPEG works:
https://en.wikipedia.org/wiki/JPEG#JPEG_codec_example

________

Also, be aware of different ways how "color" information can be represented. Common "color" models are RGB and YCbCr. The latter is used with chroma-subsampling ("Cb" and "Cr" have lower resolution than "Y").
Last edited on
Reading even a bitmap "raw" is not a task for a beginner. As part of a larger program that creates a WinAPI 2D windowed game using the GDI the program has a Bitmap class. Here's the code to read a BMP from a file:
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
BOOL Bitmap::Create(HDC hDC, LPTSTR szFileName)
{
  // Free any previous bitmap info
  Free();

  // Open the bitmap file
  HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hFile == INVALID_HANDLE_VALUE)
    return FALSE;

  // Read the bitmap file header
  BITMAPFILEHEADER  bmfHeader;
  DWORD             dwBytesRead;
  BOOL bOK = ReadFile(hFile, &bmfHeader, sizeof(BITMAPFILEHEADER),
    &dwBytesRead, NULL);
  if ((!bOK) || (dwBytesRead != sizeof(BITMAPFILEHEADER)) ||
    (bmfHeader.bfType != 0x4D42))
  {
    CloseHandle(hFile);
    return FALSE;
  }

  BITMAPINFO* pBitmapInfo = (new BITMAPINFO);
  if (pBitmapInfo != NULL)
  {
    // Read the bitmap info header
    bOK = ReadFile(hFile, pBitmapInfo, sizeof(BITMAPINFOHEADER),
      &dwBytesRead, NULL);
    if ((!bOK) || (dwBytesRead != sizeof(BITMAPINFOHEADER)))
    {
      CloseHandle(hFile);
      Free();
      return FALSE;
    }

    // Store the width and height of the bitmap
    m_iWidth = (int)pBitmapInfo->bmiHeader.biWidth;
    m_iHeight = (int)pBitmapInfo->bmiHeader.biHeight;

    // Get a handle to the bitmap and copy the image bits
    PBYTE pBitmapBits;
    m_hBitmap = CreateDIBSection(hDC, pBitmapInfo, DIB_RGB_COLORS,
      (PVOID*)&pBitmapBits, NULL, 0);
    if ((m_hBitmap != NULL) && (pBitmapBits != NULL))
    {
      SetFilePointer(hFile, bmfHeader.bfOffBits, NULL, FILE_BEGIN);
      bOK = ReadFile(hFile, pBitmapBits, pBitmapInfo->bmiHeader.biSizeImage,
        &dwBytesRead, NULL);
      if (bOK)
        return TRUE;
    }
  }

  // Something went wrong, so cleanup everything
  Free();
  return FALSE;
}

The WinAPI has been improved way beyond this to read a bitmap now you can now simply call LoadImage().
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadimagew

There are additional WinAPI libraries that can read image types like jpg and png, GDI+ is one.
https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-about-gdi--about

Direct2D is another.
https://docs.microsoft.com/en-us/windows/win32/direct2d/direct2d-overview

Both are part of modern Windows now, no need to install anything as was needed during the Win9X days.
you do not want to do this by hand. There are a small number of simple formats, like uncompressed tga, that are approximately an RGB array with a header, but the vast majority of formats have screwy stuff going on from palettes to compression. Jpeg, for example, uses a form of compression that damages the RGB data to make the files much smaller, and the BMP format dates back to the dawn of the personal computer so there are some 10 or so flavors of the format that are different from each other and a complete tool would be able to detect and read (no need to write the old ones though) all those. There are also support for various color modes beyond RGB arrays, like a G array (greyscale, one byte) or the like. Its exceedingly complicated to support by hand even the top 10 formats, and there are hundreds of formats when you get out into the obscure stuff.

However, you can just write the binary RGB array with say a 2 integer header (width, height) and some programs will read this and display it for you, and let you save it from there to a more respectable format.

the jpeg code is free, so technically you can do it without a library, but that just means pulling the code into your project directly instead, and I think its meant to be compiled to a lib so you would have to shoehorn it in.
Last edited on
Below is some more info. For example lets say my database holds these values ,as shown below.

Column 1 | Column 2 | Column 3
---------------------------------------
Image | File Name| Extension
---------------------------------------
<binary> | MyImage | PNG

So with that I want to load it up like the below. How can this be done in c++? I am trying to identify the image type, then read it, modify it and write it back.
Below is the pseudo code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
string fileName = FileNameColumnValue;
string Extension = ExtensionColumnValue;
byte[] binaryData = ImageColumnValue;

if (Extension == "PNG")
{
    fileName += ".png";
}
else if (Extension == "BMP")
{
    fileName += "..bmp";
}

FileDownload(fileName, binaryData);
the image type is tied to its extension. If that is incorrect, for many but not all types, the binary data MAY let you figure it out in code with some effort, but that is not 100% reliable for all types.

to read it, modify it, and write it back you need to use 2 libraries.
1) an image library that supports the extensions you need and
2) a database library, so you can talk to your database. ***

that conflicts with your initial post:
I am trying to see if there is a way to do this without using any third party lib functions.

but again, to recreate all that yourself is a giant project. Use the third party tools for this work. Its not exactly true to say "you can't do it without the third party libs" but you should treat it as if that were true as the work to do all this yourself would take years.

***you need that if by database, you mean a classic database that you talk to via sql or a service or something. If you just mean "my data file" when you say database, you don't need anything special. A lot of school coders have been calling disk files databases lately, and its not technically incorrect, but neither is it what the industry calls a database.
Last edited on
Do not assume "file type" (file format) and "file name extension" are the same thing.

Some file types, such as JPEG, can use different file name extensions, e.g. .jpg, .jpeg, .jpe or .jfif.

But, even more important, an "extension" is really just a part of the file name. It is a useful convention but not reliable! One can easily rename a JPEG file from .jpg to .png or even .exe. File will still be a JPEG file!

So, always detect the file type (file format) from the actual content of the file!

Pretty much all file formats start with a "magic number" that you can use to easily detect the format:
https://gist.github.com/leommoore/f9e57ba2aa4bf197ebc5

___________

But again: If you want to access (or manipulate) the actual "pixel data" of an image, then each file format (JPEG, PNG, etc.) needs to be handled differently! In order to get the "pixel data", you first need to decode the "binary" data stored in the file. And that data is totally different for each file format! That is why you will need a third-party library to decode each file format. Either that, or you will have to write your own decoder. But the latter will be a huge amount of work and requires a deep understanding of image compression...
Last edited on
I assume here that the image file is saved as a binary file. So below is what I have tried so far.
Any suggestions here?

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
#include <cinttypes>
#include <fstream>
#include <vector>

class ImgFileVector : public std::vector<uint8_t>
{
    public:

        using std::vector<uint8_t>::vector;

        void LoadImgFromFile(const char *filename)
        {
            std::ifstream file(filename, std::ios::in | std::ios::binary);
            insert(begin(),
                std::istream_iterator<uint8_t>(file),
                std::istream_iterator<uint8_t>());
        }

        void SaveImgToFile(const char *filename) const
        {
            std::ofstream file(filename, std::ios::out | std::ios::binary);
            file.write((const char *) data(), size());
            file.close();
        }
};
I'm not sure what exactly you are trying to do 😕

Your code from your last post looks like you are simply loading the image file into a vector as a sequence of bytes. In other words, you are loading the encoded (compressed) data, exactly as it is stored in the image file. Sure, you can do that. But you have to be aware that this is not the actual "pixel data" at all !!!

Originally, you said that you want to load the "pixels" from the image file and even modify them. This you can not do with the encoded (compressed) data! Instead, if you want to access the "pixels", or even modify them, then the encoded (compressed) image data, as loaded from the image file, needs to be decoded (decompressed) first! And, as explained before, this usually requires using a suitable third-party library...

So, you have to decide: Do you just want to load the "binary" image file in its encoded (compressed) form, or do you really need to access/modify the "pixel data" contained in that file ???

________

Also, I don't think loading the file contents with an iterator, i.e. in a "byte by byte" fashion, is the most efficient way. Maybe think about doing it this way, and also do proper error checking:

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
class ImgFileVector : public std::vector<uint8_t>
{
public:
	bool LoadImgFromFile(const char *const filename)
	{
		std::ifstream file(filename, std::ios::in | std::ios::binary);
		if (file.good())
		{
			const size_t file_size = fileSize(file);
			if (file.good() && (file_size > 0))
			{
				resize(file_size); // <-- adjust vector length to file size
				file.read(reinterpret_cast<char*>(data()), file_size); // <-- read whole file into vector, at once!
				return file.good();
			}
		}
		return false;
	}

private:
	static size_t fileSize(std::ifstream &file)
	{
		if (file.seekg(0, std::ios::end).good())
		{
			const std::streampos streampos_end = file.tellg();
			if (file.good())
			{
				if (file.seekg(0, std::ios::beg).good())
				{
					const std::streampos streampos_beg = file.tellg();
					if (file.good())
					{
						const std::streamoff file_size = streampos_end - streampos_beg;
						if (file_size <= SIZE_MAX)
						{
							return static_cast<size_t>(file_size);
						}
					}
				}
			}
		}
		return 0U;
};
Last edited on
I need to access/modify the "pixel data" contained in that file. There are multiple image files and format types like BMP,PNG,JPG etc. So I need to read those image files, then modify it and write back those pixels. I do understand each image format is different.
They are not only "different", most image file formats (JPEG, PNG, etc. pp.) are compressed.

This means that there is no "pixel data" stored in the file. At least not directly.

So, loading the "binary" image file into a std::vector is one thing, but it does not give you the "pixel data" !!!

In order to get the "pixel data", you would need to pass the encoded (compressed) image data, which you loaded from the file, through the suitable decoder library function. Similarly, the "pixel data" needs to be passed through the suitable encoder library function, before you can write it back to the file.


Example of how to decompress a JPEG file:
https://github.com/LuaDist/libjpeg/blob/master/example.c#L283
Last edited on
Is there any way to figure out the image file type, image file name and extension in C++, with no external libraries? I am trying to fetch these info. i understand that different image file formats are chosen based on the filename extension.

Below is some more info. For example lets say my database holds these values ,as shown below.

Column 1 | Column 2 | Column 3
---------------------------------------
Image | File Name| Extension
---------------------------------------
<binary> | MyImage | PNG
Last edited on
Is there any way to figure out the image file type, image file name and extension in C++, with no external libraries?

Yes, Use <filesystem> to get name and extension. Parse the file's header section for the image type, hard-coded for each and every image type there is.

But what if the image doesn't follow that standard? RAW format images comes to mind.

Are you sure you want to spend months and years duplicating work hundreds of people have already done? That is potentially a serious waste of time, except for the ephemeral "gee I want to know" learning experience.

I'd use a 3rd party library and at the same time research the inner workings of the more common image file formats so I can appreciate the work I don't have to do by writing my own and very likely flawed methods.
Is there any way to figure out the image file type, image file name and extension in C++, with no external libraries? I am trying to fetch these info. i understand that different image file formats are chosen based on the filename extension.

Figuring out the file name and file name extension is a simple string operation, if you already have the path to the file as a path string — which you are going to need anyway, if you want to open/read that file. The file name simply is the part of the path string that follows after the last slash (/) or backslash (\) character. And the file name extension simply is the part of the file name following after the last dot (.) character.

But, again, be aware that the file name extension only gives you a hint on what the file contents (file format) might be, but certainly should not be treated as a reliable indicator of the file format! As said before, most image file formats start with a "magic number" (characteristic byte sequence) that you can easily detect:
https://gist.github.com/leommoore/f9e57ba2aa4bf197ebc5

Note: Knowing the file format does not yet give you the "pixel data" though! It is only the first step to select the proper decoding routine that you'll need to decode the "pixel data" from the "encoded" file contents...
Last edited on
You can find the list of magic numbers in the github that kigar64551 gave you. Here's a smashed together example of checking if "file.png" truly contains data for a png formatted file using the magic number:
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
#include <fstream>
#include <iostream>

// return true if the magic number is found
bool isPng(char * buffer)
{
        if((unsigned char) buffer[0] == 0x89 && buffer[1] == 0x50 && buffer[2] == 0x4E && buffer[3] == 0x47)
        {
                return true;
        }
        return false;
}

int main()
{
        char buffer[1024] = {0}; // arbitrary size, likely you're going to be using a vector to hold the data.
        std::ifstream inFile("file.png", std::ios::binary);
        if(inFile.good())
        {
                inFile.read(buffer, 4);
        }
        inFile.close();
        if(isPng(buffer))
        {
                std::cout << "Yup, that's a png." << std::endl;
        }
}

Again, Kigar's posted link contains a table of magic numbers you can use to identify the actual file format.
Last edited on
Be careful with that stuff though. IIRC, bmp alone has like 5 'magic' numbers, and I am not sure some of the older formats have such a thing, though all the common in use ones will.
Topic archived. No new replies allowed.