I am having some trouble playing around with files. Here is what I am trying to accomplish. I am attempting to filter a PPM image by take the inverse of the blue value (every third value). I can successfully open and write files, but I am experiencing some issues. In my while (myfile.good()) loop, I think only the final 3 numbers get assigned to the variables r, g, and b. What I am trying to do is have every first( out of three) value assigned to the variable r, every second value assigned to g, and every third value assigned to b. However, I want to take 255 - the current b value, and set that as the new b value to apply to filter. Do I have to make 3 separate files (1 for each variable), and then open them all to write them in a 4 file which would serve as the final copy? Or is there a way to copy them all and assign it to a variable? Any help is much appreciated. I am new to c++ so please forgive me. Thank you for your assistance.
Example of values I am attempting to use: http://imgur.com/H6EDFIq
#include <iostream>
#include <cmath>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
char filename[50];
ifstream myfile;
cin.getline(filename, 50);
myfile.open(filename);
if(!myfile.is_open())
{
cout << "File cannot load.";
}
char r [50];
char g [50];
char b [50];
myfile >> r >> g >> b;
while (myfile.good())
{
myfile >> r >> g >> b;
}
myfile.close();
ofstream myfile2;
myfile2.open(filename);
//this is just to test to see what gets written onto the file
//for (int a=0; a<20; a++)
//{
// ** Is this even allowed?? int r = 255 - r;
//myfile2 << r << " " << g << " " << b;
//}
myfile2.close();
return 0;
}
Unless you have a particular need to store the data in memory then it's simpler to just write the data to a new file as you read it.
Here's an example that reads a P3 ppm with 8-bit color entries, inverts the blue channel as you requested, then writes a new file with that data. It doesn't do a ton of error checking but I didn't want to make it any longer than it already is. You'll want to add your own filename prompting and such.
#include <iostream>
#include <string>
#include <fstream>
int main()
{
std::ifstream inFile("lena.ppm");
if(!inFile)
{
std::cerr << "Could not open input file.\n";
return -1;
}
std::string type;
std::string comment;
int width = 0, height = 0, colors = 0;
std::getline(inFile, type);
if(type != "P3")
{
std::cerr << "File is not a P3 format PPM.\n";
return -1;
}
if(inFile.peek() == '#')
{
std::getline(inFile, comment);
}
inFile >> width >> height >> colors;
std::ofstream outFile("lena2.ppm");
if(!outFile)
{
std::cerr << "Could not open output file.\n";
return -1;
}
outFile << type << "\n";
if(!comment.empty())
{
outFile << comment << "\n";
}
outFile << width << " " << height << "\n" << colors << "\n";
for(int y = 0; y < height; ++y)
{
for(int x = 0; x < width; ++x)
{
int r = 0, g = 0, b = 0;
if(!(inFile >> r >> g >> b))
{
std::cerr << "File ended early.\n";
return -1;
}
b = (255 - b);
if(x != 0 && !(x % 5)) //Keep lines under 70 columns per spec.
{
outFile << "\n";
}
outFile << r << " " << g << " " << b << " ";
}
outFile << "\n";
}
return 0;
}
You'll want to check for a .ppm header which is the first line of the .ppm image. Check out .ppm magic numbers, either P3 or P6 and you'll need to check for that. Second line are the dimensions of the image, so you'll need to take that into consideration too.
This is something I worked on earlier so you can get an idea. It might not work immediately so just give it a read.
#include <iostream>
#include <fstream>
#include <sstream>
#include <exception>
int main() {
std::string filename = //whatever your file name is
std::ifstream input(filename.c_str(), std::ios::in | std::ios::binary);
if (input.is_open()) {
std::string line;
std::getline(input, line);
if (line != "P6" || line != "P3" ) { //you're going to want to check if you're using P3 or P6
//print out errors
}
std::stringstream image_dimensions(line);
try {
image_dimensions >> w //your width variable if you want to store it here
image_dimensions >> h //your height variable if you want to store it here
} catch (std::exception &e) {
std::cout << "Format error found in header " << e.what() << std::endl;
return;
}
int size = w*h;
std::getline(input, line);
std::stringstream max_value(line); //max colour value of the image
//you can initialise the vectors here if you want
std::vector<unsigned char> r;
std::vector<unsigned char> g;
std::vector<unsigned char> b;
//we know it max capacity so reserve that size for the vectors
r.reserve(size);
g.reserve(size);
b.reserve(size);
char read_rgb;
for (unsigned int i = 0; i < size; ++i) {
input.read(&read_rgb, 1);
r[i] = (unsigned char) read_rgb;
input.read(&read_rgb, 1);
g[i] = (unsigned char) read_rgb;
input.read(&read_rgb, 1);
b[i] = (unsigned char) read_rgb;
}
}
input.close();
}
You'll want to store r,g,b as arrays of your choosing. Once you've done that, you can just iterate over the array of B and edit it to apply your filter and then just write it to a ppm file.
Also, for error handling, you can always open up the .ppm file using Notepad or Notepad++ and read the image.
Related
I am trying to figure out how to extract values from a text file as a type double so that they can be used in calculations.
I have a text file that is formatted like:
parameter1 parameter2 parameter3
50 0 0.1
And I want to extract only the numbers.
This is one of my attempts (I have been working for hours trying to figure out how to do this).
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
const int MAX = 80;
char buffer[MAX];
string input;
double j;
ifstream param0;
param0.open("param0.txt");
char ch;
while (param0)
{
param0.get(ch);
cout << ch;
}
getline(param0, input);
param0 >> j;
while (param0)
{
cout << j << endl;
getline(param0, input);
param0 >> j;
}
return 0;
}
this code
char ch;
while (param0)
{
param0.get(ch);
cout << ch;
}
runs to the end of the file. All reads after it will return nothing. Either take this loop out or rewind the file param0.rewind()
The basic idea of the code should be:
std::string line;
double p1, p2, p3;
std::string more;
while (std::getline(in, line)) {
std::istringstream iss{line};
if (iss >> p1 >> p2 >> p3 && !(iss >> more)) {
std::printf("p1=%f, p2=%f, p3=%f\n", p1, p2, p3);
} else {
std::printf("invalid line: %s\n", line.c_str());
}
}
In plain words, the code says: a line is valid if it contains three numbers and nothing more.
C++ purists will say that I shouldn't use printf in C++, but I like the separation between formatting and the actual data.
suggestion :
best to check if you open the file correctly.
close the file once you finish with it.
you can just use the >> operator if you reading everything in one line. It doesn't matter if its string or double as long as if you pass the correct storage variable;
string param1;
string param2;
string param3;
double j,k,l;
ifstream file("test.txt",std::ios::in);
if (!file.is_open())
std::cout << "failed to open " << endl;
while (file)
{
file >> param1 >> param2 >>param3; // getting as strings
cout << param1 <<", "<< param2<<", "<< param3<<endl;
file >> j >> k >> l; //getting as doubles
cout << j <<", " << k <<", " << l<<endl;
}
file.close();
return 0;
output
parameter1, parameter2, parameter3
50, 0, 0.1
just want to ask if anyone knows why I cant convert an entire picture into decimal.
Problem: after about 180 couts it turns 0 for the rest of the pixels.
Code:
#include <fstream>
#include <iostream>
int main() {
char unsigned charTemp = 0;
int unsigned intTemp = 0;
std::fstream file;
file.open("PIC.pbm", std::ios::in);
//Ignore header
for (int i = 0; i < 13; i++) {
file.ignore();
}
//read and print
//img res is 40x40 = 1600
for (int i = 0; i < 1600; i++) {
file >> charTemp;
intTemp = charTemp;
std::cout << intTemp << " ";
charTemp = 0;
intTemp = 0;
}
std::cout << "\n\n\n";
system("pause");
return 0;
}
Pic: any 40x40 pbm
A better method with picture and image files is to read them as binary files:
std::ifstream file("PIC.pbm", ios::binary);
std::vector<unsigned char> bitmap(1600);
// Skip over the header
file.seekg(13, ios::beg); // Skip over 13 bytes.
// Read in the data at once
file.read((char *) &bitmap[0], 1600);
// Now process the bitmap from memory
for (int i = 0; i < 1600; ++i)
{
cout << static_cast<unsigned int>(bitmap[i]) << " ";
if ((i % 40) == 39)
{
cout << "\n";
}
}
cout << "\n";
The idea here is to read in the bitmap in one transaction into memory. Streams like to flow (don't interrupt the flow). Memory is faster to access than files, so the bitmap values are processed from memory.
The cast is used so that the formatted insertion doesn't treat the byte as a character, but a number.
First, open your PIC.pbm file in another hex editor because it's quite possible that those bytes really are zeroes. If not, then you've got problems reading the file.
The fstream constructor does not default to reading in binary mode, so it reads files as "text" - and I've learned the hard way that you can't trust the standard-library with knowing anything about text anymore (what with mishandling Unicode, line-endings, etc - I feel it's best to always use binary and a dedicated Unicode library).
You should check the fstream::good() function after each read operation to see if it failed, and if so, then check iostate:
using namespace std;
// ...
fstream file;
file.open( "PIC.pbm", ios::in | ios::binary );
file.ignore( 13 );
for (int i = 0; i < 1600; i++) {
file >> charTemp;
if( !file.good() ) {
cout << endl;
cout << "Error reading file: iostate == " << file.iostate << endl;
break;
}
else {
intTemp = charTemp;
std::cout << intTemp << " ";
charTemp = 0;
intTemp = 0;
}
}
I'm working on a code that reads in a C++ source file and converts all ‘<’ symbols to “<” and all ‘>’ symbols to “>”. I wrote out the main method and everything compiled nicely but now that I'm actually writing out my convert function at the top of the program, I'm stuck in an infinite loop and I'm hitting a wall on what the culprit is. Could someone help me out?
I included the whole program in case the problem lies in my I/O coding but I surrounded the function with slashes. Hopefully I won't get flamed.
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
//FUNCTION GOES THROUGH EACH CHARACTER OF FILE
//AND CONVERTS ALL < & > TO < or > RESPECTIVELY
//////////////THIS IS THE FUNCTION IN QUESTION//////////
void convert (ifstream& inStream, ofstream& outStream){
cout << "start" << endl;
char x;
inStream.get(x);
while (!inStream.eof()){
if (x == '<')
outStream << "<";
else if (x == '>')
outStream << ">";
else
outStream << x;
}
cout << "end" << endl;
};
///////////////////////////////////////////////////////////////////////////
int main(){
//FILE OBJECTS
ifstream inputStream;
ofstream outputStream;
string fileName;
//string outFile;
//USER PROMPT FOR NAME OF FILE
cout << "Please enter the name of the file to be converted: " << endl;
cin >> fileName;
//outFile = fileName + ".html";
//ASSOCIATES FILE OBJECTS WITH FILES
inputStream.open(fileName.c_str());
outputStream.open(fileName + ".html");
//CREATES A CONVERTED OUTPUT WITH <PRE> AT START AND </PRE> AT END
outputStream << " <PRE>" << endl;
convert(inputStream, outputStream);
outputStream << " </PRE>" << endl;
inputStream.close();
outputStream.close();
cout << "Conversion complete." << endl;
return 0;
}
It isn't a good approach to manipulate a file while you're reading it. The right way is, first read the whole file, store the data, manipulate the stored data, and then update the file. Hope this code will help you :)
void convert()
{
int countLines = 0; // To count total lines in file
string *lines; // To store all lines
string temp;
ifstream in;
ofstream out;
// Opening file to count Lines
in.open("filename.txt");
while (!in.eof())
{
getline(in, temp);
countLines++;
}
in.close();
// Allocating Memory
lines = new string[countLines];
// Open it again to stroe data
in.open("filename.txt");
int i = 0;
while (!in.eof())
{
getline(in, lines[i]);
// To check if there is '<' symbol in the following line
for (int j = 0; lines[i][j] != '\0'; j++)
{
// Checking the conditon
if (lines[i][j] == '<')
lines[i][j] = '>';
}
i++;
}
in.close();
// Now mainuplating the file
out.open("filename.txt");
for (int i = 0; i < countLines; i++)
{
out << lines[i];
if (i < countLines - 1)
out << endl;
}
out.close();
}
I have been looking for an error in a code that I am using for finite element methods. The point is that I have to get some data from a file to identify the material of a cell. The type of this material_id is unsigned char , and here is the problem.
When reading the data from the file, different ways to assign the value to a unsigned char variable gives different result. I have fixed the problem, but I am still wondering why it is working in a different way. Here you have a sample code reproducing the different behavior:
#include <map>
#include <sstream>
#include <fstream>
#include <string>
#include <iostream>
#include <vector>
#include <stdlib.h>
namespace types
{
//typedef unsigned int material_id;
typedef unsigned char material_id;
}
namespace Utilities
{
int string_to_int(const std::string & str)
{
return atoi(str.c_str());
}
}
template<typename Number>
void parseVector_1(std::ifstream & myfile,
std::vector<Number> & mat_id)
{
Number num;
std::string line, bin;
if (myfile.is_open())
{
getline (myfile,line);
std::istringstream iss(line);
while ( iss.good() )
{
iss >> bin; // option 1
num = Utilities::string_to_int(bin); // option 1
mat_id.push_back(num);
}
}
else std::cout << "Unable to open file";
}
template<typename Number>
void parseVector_2(std::ifstream & myfile,
std::vector<Number> & mat_id)
{
Number num;
std::string line, bin;
if (myfile.is_open())
{
getline (myfile,line);
std::istringstream iss(line);
while ( iss.good() )
{
iss >> num; // option 2
mat_id.push_back(num);
}
}
else std::cout << "Unable to open file";
}
int main()
{
unsigned int n_mat;
std::vector<types::material_id> mat_id_1;
std::vector<types::material_id> mat_id_2;
std::map<types::material_id, double> D1v;
D1v[0] = 0.0;
D1v[1] = 1.0;
D1v[2] = 2.0;
D1v[3] = 3.0;
D1v[4] = 4.0;
std::ifstream myfile1 ("materials.dat");
parseVector_1(myfile1, mat_id_1);
myfile1.close();
std::ifstream myfile2 ("materials.dat");
parseVector_2(myfile2, mat_id_2);
myfile2.close();
n_mat = mat_id_1.size();
std::cout << "option 1: ";
for (unsigned int i = 0; i < n_mat; ++i)
std::cout << "mat["<<i<<"]=" << D1v[mat_id_1[i]] << " ";
std::cout << std::endl;
n_mat = mat_id_2.size();
std::cout << "option 2: ";
for (unsigned int i = 0; i < n_mat; ++i)
std::cout << "mat["<<i<<"]=" << D1v[mat_id_2[i]] << " ";
std::cout << std::endl;
return 0;
}
The content of the "materials.dat" file is the following line:
0 1 2 3 4
And here is the output of the execution:
$ unsignedchar_problem.exe
option 1: mat[0]=0 mat[1]=1 mat[2]=2 mat[3]=3 mat[4]=4
option 2: mat[0]=0 mat[1]=0 mat[2]=0 mat[3]=0 mat[4]=0 mat[5]=0
Can anyone give some insight why option 1 is working fine, but option 2 is not? Is it dependent on the compiler/platform of it is always like that?
As an additional information, the problem was because the material_id type was defined as unsigned int by the other user in his computer, so it was working without any problem.
Extracting unsigned char from an istream reads a single character and stores that character's numeric value into the destination variable. So mat_id_2[0] will contain the numeric value of '0', which is probably 48 (if your system is ASCII).
Extracting a non-chararacter integral type will read an integer and store the value of that integer, as you were expecting.
I'm a physics PhD student with some experience coding in java, but I'm trying to learn C++.
The problem I'm trying to solve is to read in data from a .txt file and then output all the numbers > 1000 in one file and all those <1000 in another.
What I need help with is writing the part of the code which actually reads in the data and saves it to an array. The data itself is only separated by a space, not all on a new line, which is confusing me a bit as I don't know how to get c++ to recognise each new word as an int. I have canabalised some code I have got from various sources online-
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
#include<cmath>
using namespace std;
int hmlines(ifstream &a) {
int i=0;
string line;
while (getline(a,line)) {
cout << line << endl;
i++;
}
return i;
}
int hmwords(ifstream &a) {
int i=0;
char c;
a >> noskipws >> c;
while ((c=a.get()) && (c!=EOF)){
if (c==' ') {
i++;
}
}
return i;
}
int main()
{
int l=0;
int w=0;
string filename;
ifstream matos;
start:
cout << "Input filename- ";
cin >> filename;
matos.open(filename.c_str());
if (matos.fail()) {
goto start;
}
matos.seekg(0, ios::beg);
w = hmwords(matos);
cout << w;
/*c = hmchars(matos);*/
int RawData[w];
int n;
// Loop through the input file
while ( !matos.eof() )
{
matos>> n;
for(int i = 0; i <= w; i++)
{
RawData[n];
cout<< RawData[n];
}
}
//2nd Copied code ends here
int On = 0;
for(int j =0; j< w; j++) {
if(RawData[j] > 1000) {
On = On +1;
}
}
int OnArray [On];
int OffArray [w-On];
for(int j =0; j< w; j++) {
if(RawData[j]> 1000) {
OnArray[j] = RawData[j];
}
else {
OffArray[j] = RawData[j];
}
}
cout << "The # of lines are :" << l
<< ". The # of words are : " << w
<< "Number of T on elements is" << On;
matos.close();
}
But if it would be easier, i'm open to starting the whole thing again, as I don't understand exactly what all the copied code is doing. So to summarise, what I need is it to-
Ask for a filepath in the console
Open the file, and store each number (separated by a space) as an element in a 1D array
I can manage the actual operations myself I think, if I could just get it to read the file the way I need.
Thanks very much
Using C++11 and the Standard Library makes your task fairly simple. This uses Standard Library containers, algorithms, and one simple lambda function.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>
int main()
{
std::string filename;
std::cout << "Input filename- ";
std::cin >> filename;
std::ifstream infile(filename);
if (!infile)
{
std::cerr << "can't open " << filename << '\n';
return 1;
}
std::istream_iterator<int> input(infile), eof; // stream iterators
std::vector<int> onvec, offvec; // standard containers
std::partition_copy(
input, eof, // source (begin, end]
back_inserter(onvec), // first destination
back_inserter(offvec), // second destination
[](int n){ return n > 1000; } // true == dest1, false == dest2
);
// the data is now in the two containers
return 0;
}
Just switch the type of variable fed to your fistream, created from new std:ifstream("path to file") into a int and c++ will do the work for you
#include <fstream> //input/output filestream
#include <iostream>//input/output (for console)
void LoadFile(const char* file)
{
int less[100]; //stores integers less than 1000(max 100)
int more[100]; //stores integers more than 1000(max 100)
int numless = 0;//initialization not automatic in c++
int nummore = 0; //these store number of more/less numbers
std::ifstream File(file); //loads file
while(!file.eof()) //while not reached end of file
{
int number; //first we load the number
File >> number; //load the number
if( number > 1000 )
{
more[nummore] = number;
nummore++;//increase counter
}
else
{
less[numless] = number;
numless++;//increase counter
}
}
std::cout << "number of numbers less:" << numless << std::endl; //inform user about
std::cout << "number of numbers more:" << nummore << std::endl; //how much found...
}
This should give you an idea how should it look like(you shoudnt use static-sized arrays tough) If you got any probs, comment back
Also, please try to make nice readable code, and use tabs/ 4 spaces.
even though its pure C, this might give you some hints.
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
#define MAX_LINE_CHARS 1024
void read_numbers_from_file(const char* file_path)
{
//holder for the characters in the line
char contents[MAX_LINE_CHARS];
int size_contents = 0;
FILE *fp = fopen(file_path, "r");
char c;
//reads the file
while(!feof(fp))
{
c = fgetc(fp);
contents[size_contents] = c;
size_contents++;
}
char *token;
token = strtok(contents, " ");
//cycles through every number
while(token != NULL)
{
int number_to_add = atoi(token);
//handle your number!
printf("%d \n", number_to_add);
token = strtok(NULL, " ");
}
fclose(fp);
}
int main()
{
read_numbers_from_file("path_to_file");
return 0;
}
reads a file with numbers separated by white space and prints them.
Hope it helps.
Cheers