Image fading help needed C++

Pages: 123
Yes, pixelData must be unsigned char here.
but how can I use vector?
Below is the targa writer, but cant get it to work. what could be wrong here? please help me.

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
#include <fstream.h>
#include <iostream.h>

typedef unsigned char UCHAR;
typedef signed char SCHAR;
typedef unsigned short int USINT;

class TARGA
{
public:
TARGA();
UCHAR idLength; // no. of chars in id field.
UCHAR colorMapType; // 1 = map 0 = no map
UCHAR imageType; // 1 = color mapped, 2 = rgb, 3 = b&w. All uncompressed
USINT colorMapStart; // index of first entry (lo-hi)
USINT colorMapNumEntries; // no. of color map entries (lo-hi)
UCHAR bitPerEntry; // 16 for 16bit, 24 for 24bit...
USINT xOrigin; // lower left corner (lo-hi)
USINT yOrigin; // lower left corner (lo-hi)
USINT width; // width of image (lo-hi)
USINT height; // height of image (lo-hi)
UCHAR bitsPerPixel; // 16 for 16bit, 24 for 24bit...
UCHAR pixelData;
UCHAR* image_data; // data stored differently depending on bitrate and colormap etc.
// The footer is ignored
};
TARGA::TARGA()
{
idLength = 0;
colorMapType = 0;
imageType = 2; // truecolor
colorMapStart = 0;
colorMapNumEntries = 0;
bitPerEntry = 24; // 24 bit
xOrigin = 0;
yOrigin = 0;
width = 2; // width
height = 2; // height
bitsPerPixel = 24; // 24 bit
pixelData = 0;

image_data = new UCHAR[width*height*3];

for (int n=0; n<width*height*3; n++)
{
	image_data[n]= 128; // should make all pixels gray
}
}

main(int argc, char* argv)
{
fstream file;
TARGA targa;

char outfile[] = "outtest.tga";

file.open(outfile, ios::out | ios::binary);	
if (!file)
{
	cout << "Error in opening " << outfile << " for writing tga" << endl;
	return 1;
}

file.write((UCHAR *)&targa,sizeof(targa));
file.close();

file.open(outfile, ios::in | ios::binary);
if (!file)
{
	cout << "Error in opening " << outfile << " for reading tga" << endl;
	return 1;
}

char c;
int n=0;
while (true)
{
	file.get(c);
	cout << n << ": " << int(c) << endl;

	if (file.eof()) { break; }
	
	n++;
}
//file.read((UCHAR *)&targa,sizeof(targa));
file.close();


return 0;
}
looks close.
you can't read and write (literally read() and write()) data with pointers in it.
you can either make the data part a fixed sized array (and do not write() the size of the object but the size of the image) that is big enough for any image you are working with or you can leave it a pointer and do a write() of the header part and then another write() of the pointer data.

an easy way to do this is make a struct/class of everything but the data (just take UCHAR* image_data; out of the class) and have a has-a class with
class targa
{
header h; //everything else in the header or whatever name class
UCHAR* image_data;
}

then your broken line 64 becomes
file.write(targa.h, sizeof(targa.h));
file.write(targa.image_data, w*h*3);

and line 85 would work too, after you allocated the pointer's memory.
by the way, where did you do that for the first one.. if you gonna use a pointer, you need to allocate memory for it... I think you forgot that step.

there are over 50 names for the int types (8, 16, 32 and 64 signed and unsigned is 8 total types) in c++ already. Surely, one of those will do without making more?

yet *another* way to do this is to use all pointers in your targa class and just take hard-coded offsets.
eg
class targa
{
uint8_t * data; //everything, read the whole binary file into this after allocating space
uint8_t * length = &data[0];
uint8_t* colormap = &data[1];
...
and yes with a cast
uint16_t *colormapstart = (uint16_t*) &data[whatever offset];
}
there are other ways to do the above (including using 2 classes, one with fields that can over-cast onto the byte blob, its only purpose is to define the cast operation!)
but the idea is you can read and write in one read() or write() like you were trying to do, and just reshape the bytes into human code format by brute force.
Last edited on
Hi Jonnin

I have modified the code, but got strange errors. It might be something stupid, but I need your help to make the code to work.

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
#include <fstream>
#include <iostream>

typedef unsigned char UCHAR;
typedef signed char SCHAR;
typedef unsigned short int USINT;

struct targa{
header h;
UCHAR* image_data; // here the data stored differently depending on bitrate and colormap etc.
};

class TARGA
{
public:
TARGA();
UCHAR idLength; // no. of chars in id field.
UCHAR colorMapType; // 1 = map 0 = no map
UCHAR imageType; // 1 = color mapped, 2 = rgb, 3 = b&w. All uncompressed
USINT colorMapStart; // index of first entry (lo-hi)
USINT colorMapNumEntries; // no. of color map entries (lo-hi)
UCHAR bitPerEntry; // 16 for 16bit, 24 for 24bit...
USINT xOrigin; // lower left corner (lo-hi)
USINT yOrigin; // lower left corner (lo-hi)
USINT width; // width of image (lo-hi)
USINT height; // height of image (lo-hi)
UCHAR bitsPerPixel; // 16 for 16bit, 24 for 24bit...
UCHAR pixelData;

// The footer is ignored
};
TARGA::TARGA()
{
idLength = 0;
colorMapType = 0;
imageType = 2; // truecolor
colorMapStart = 0;
colorMapNumEntries = 0;
bitPerEntry = 24; // 24 bit
xOrigin = 0;
yOrigin = 0;
width = 2; // width
height = 2; // height
bitsPerPixel = 24; // 24 bit
pixelData = 0;

image_data = new UCHAR[width*height*3];

for (int n=0; n<width*height*3; n++)
{
	image_data[n]= 128; // should make all pixels gray
}
}

int main(int argc, char** argv)
{
fstream file;
TARGA targa;

char outfile[] = "outtest.tga";

file.open(outfile, std::ios::out | std::ios::binary);	
if (!file)
{
	std::cout << "Error in opening " << outfile << " for writing tga" << std::endl;
	return 1;
}

file.write((UCHAR *)&targa.h,sizeof(targa.h));
file.write((UCHAR *)targa.image_data, w*h*3);
file.close();

file.open(outfile, std::ios::in | std::ios::binary);
if (!file)
{
	std::cout << "Error in opening " << outfile << " for reading tga" << std::endl;
	return 1;
}

char c;
int n=0;
while (true)
{
	file.get(c);
	std::cout << n << ": " << int(c) << std::endl;

	if (file.eof()) { break; }
	
	n++;
}
file.read((UCHAR *)&targa,sizeof(targa));
file.close();


return 0;
}



9:1: error: 'header' does not name a type
In constructor 'TARGA::TARGA()':
47:1: error: 'image_data' was not declared in this scope
In function 'int main(int, char**)':
57:1: error: 'fstream' was not declared in this scope
57:1: note: suggested alternative:
In file included from /usr/include/c++/4.9/ios:38:0,
from /usr/include/c++/4.9/istream:38,
from /usr/include/c++/4.9/fstream:38,
from 1:
/usr/include/c++/4.9/iosfwd:163:33: note: 'std::fstream'
typedef basic_fstream<char> fstream;
^
62:1: error: 'file' was not declared in this scope
69:28: error: 'class TARGA' has no member named 'h'
69:43: error: 'class TARGA' has no member named 'h'
70:27: error: 'class TARGA' has no member named 'image_data'
70:39: error: 'w' was not declared in this scope
70:41: error: 'h' was not declared in this scope
Last edited on
> Below is the targa writer, but cant get it to work. what could be wrong here? please help me.
"Your" code is 20 years old.
https://cboard.cprogramming.com/cplusplus-programming/12412-need-help-tga-writer.html

Even your original post seems like code you found.
https://stackoverflow.com/questions/66142019/blurring-an-image-using-gaussian-blur-in-c
https://cboard.cprogramming.com/c-programming/166823-image-blur-filter.html

The problem is you don't know any C or C++ at all. Least not enough to make an actual contribution.

Your attempt to follow jonnin's suggestions as being instructions to copy/paste only resulted in you digging a much bigger hole for yourself.

Your google + copy/paste + bleating "please help" approach isn't going to work.
Hi salem c

I am using the code for learning purpose only here, as i am newbie to image processing.
Any suggestions for the below ?
For the image manipulation and to do write operation is as follows:

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
#include <fstream>
#include <string>
using namespace std;

#define BYTERANGE 255

typedef unsigned char sample;
typedef struct
  {
  sample red, green, blue;
  }
  IMG_RGB;

bool writetarge( const string& files, IMG_RGB* info, unsigned w, unsigned h)
  {
  ofstream file(files.c_str(), ios::out | ios::binary);
  if (!file) return false;

  // img hdr
  sample hdr[ 18 ] = { 0 };
  hdr[  2 ] = 1;  
  hdr[ 12 ] =  w        & BYTERANGE;
  hdr[ 13 ] = (w  >> 8) & BYTERANGE;
  hdr[ 14 ] =  h       & BYTERANGE;
  hdr[ 15 ] = (h >> 8) & BYTERANGE;
  hdr[ 16 ] = 24;  

  file.write((const char*)hdr, 18);

  for (int j = h -1; j >= 0; j--)
  for (int i = 0; i < w; i++)
    {
      file.put( (char)info[ (j * w) + i ].blue  );
      file.put( (char)info[ (j * w) + i ].green );
      file.put( (char)info[ (j * w) + i ].red   );
    }

  file.close();
  return true;
  }
Last edited on
why are you writing it one byte at a time?
this is complete gibberish. It may work, but it has C style typedefs and structs, once again we have yet another name for uint8_t, this time a hard to type one, and why? Its broken up by pixels due to the struct, which is completely unnecessary. It accesses a 1-d array with 2-d logic, why? just iterate across a row of pixels; if you need random pixel access, we can do that after you get something to work.

The first example was fine, you just needed to fix how you write the file out.

Copying off the web is fine. I do it all the time. But you have to be able to hack on it if you want it to do something different from what it did originally, which means being able to read and write c++ -- the fact that they are images is not relevant here, everything you are doing in these is pure c and c++ (if a bit dated).
whats wrong with the original is that I called the second struct approach header and you called it lowercase targa. the names don't matter to the compiler, but you need to match it all up to make it work... and its helpful to use good names so people can follow it.

do you actually know c++? Its ok to be a beginner, but you don't walk into shop class and say "im gonna build a car" you say "im gonna build a hatrack". This may be too much for you (your original constraints, it surely will be, targa is the easy format, jpg requires a wavelet transform and manipulation of the resulting zeros for compression).
> I am using the code for learning purpose only here, as i am newbie to image processing.
Along with being a newbie to programming TBH.

The problem with copy/paste is that your only idea of what the code does is from reading the comments and because that matched your google search.

What it does do is completely mis-represent your actual skill level. We see code (of some quality) and tune answers to match the perceived skill of the poster. In your case, this has been consistently way over your head.

So here we are, a week and 50 posts later, and you're no closer to an answer and we're still in the dark as to what you really want, and what you're really capable of doing.

I took 10 min crack at the first one.

this works. the tga file I wrote opens in my image editing software. The image I read in has the correct dimensions.
maybe you can do something with it from here. I just took the 'make it work' approach... it may need more work and cleanup.
See if you can hack out what you need here. image_data is iterateble ... typically something like
for(i = 0; i < width*height*3; i+=3)
{
image_data[0] = something; //do something with red
image_data[1] = something; //green
image_data[2] = something; //blue
}

why not take this code, see if it generates a targa you can read in 3rd party image editor that still supports the format, and then if that works, see if you can use the filter I gave you to drive the color brightness/extremes down as an exercise?


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

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <fstream>
#include<vector>
#include <numeric>
#include <cmath>
#include <iostream>
#include <cstring>
using namespace std;


struct tgaheader
{
uint8_t idLength{}; // no. of chars in id field.
uint8_t colorMapType{}; // 1 = map 0 = no map
uint8_t imageType{2}; // 1 = color mapped, 2 = rgb, 3 = b&w. All uncompressed
uint16_t colorMapStart{}; // index of first entry (lo-hi)
uint16_t colorMapNumEntries{}; // no. of color map entries (lo-hi)
uint8_t bitPerEntry{}; // 16 for 16bit, 24 for 24bit... unused if no colormap...
uint16_t xOrigin{}; // lower left corner (lo-hi)
//uint16_t yOrigin{}; // lower left corner (lo-hi)
///SOMETHING IS WRONG HERE, THE WEB VS MY TGA READER (LAZ PAINT PORTABLE) 
///WITH THE EXTRA 2 BYTE FIELD REMOVED IT IS FINE IN LAZ.  WIKI DOES NOT MATCH. 

uint16_t width{2}; // width of image (lo-hi)
uint16_t height{2}; // height of image (lo-hi)
uint8_t bitsPerPixel{24}; // 16 for 16bit, 24 for 24bit...
uint8_t pixelData{};
// The footer is ignored
};



struct targa
{
  tgaheader h;
  uint8_t* image_data{nullptr}; // here the data stored differently depending on bitrate and colormap etc.
  
  targa(uint16_t w, uint16_t hite, uint8_t* pic = nullptr)
  {
     h.width = w;
     h.height = hite;
     image_data = pic;
	 if(!pic)
	 {
		 image_data = new uint8_t[h.width*h.height*3];	  	  
	 }
  }
  targa()
  {
     image_data = new uint8_t[h.width*h.height*3];	  	  
  }
  ~targa()
  {
    delete[] image_data;	  
  }
  void read(ifstream &ifs)
  {
	  ifs.read((char*)&h, sizeof(h));	  
	  delete[] image_data;
	  image_data = new uint8_t[h.width*h.height*3];	  	  
	  ifs.read((char*)image_data, h.width*h.height*3);
  } 
  void write(ofstream &ofs)
  {
	  ofs.write((char*)&h, sizeof(h));
	  ofs.write((char*)image_data, h.width*h.height*3);
  }  
};

int main(int argc, char** argv)
{
ofstream file;
targa tga;

char outfile[] = "outtest.tga";

file.open(outfile, std::ios::out | std::ios::binary);	
if (!file)
{
	std::cout << "Error in opening " << outfile << " for writing tga" << std::endl;
	return 1;
}

memset(tga.image_data, 128, tga.h.height*tga.h.width*3);
tga.write(file);

ifstream ifs;
ifs.open("tst.tga", std::ios::out | std::ios::binary);	
tga.read(ifs);
cout << tga.h.width << endl << tga.h.height << endl;  

return 0;

}



edit, checked a second image viewer and it also took the resulting file.
there must be something we missed in the spec, to be off by 2 bytes ... maybe the palette section has an optional field and we are not using that area... ? Must have misread something or the wiki may be poorly worded but correct, I do not know. I know the binary is right as-is, but the actual field that is misplaced may be different...
Last edited on
Topic archived. No new replies allowed.
Pages: 123