This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
logsys's profile picture

Print Screen into a file

Started by logsys, 22 February 2014 - 05:32 AM
logsys #1
Posted 22 February 2014 - 06:32 AM
I have this thing here:
————————-
| |
| Name: |
| Join date: |
| IG Country: |
| IG City: |
| IG Address: |
| Real Country: |
| Real 1st name: |
| Rank: |
| |
| |
| Reffering City: |
| |
| |
————————-
it's not properly formated here, but it is placed on the screen with the following coords: Top Left Corner(1,1) Bottom Right Corner(26,16).



I want to save these coords to a file as I will modify some parts of it on the screen.
What code can I use to "print screen" and save the file?
CometWolf #2
Posted 22 February 2014 - 06:41 AM
Provided you do term.setCursorPos(1,1) before printing it, it will be rendered at the same spot regardless of what you do before or after, unless you overwrite it.
Bomb Bloke #3
Posted 22 February 2014 - 06:50 AM
If you just want to be able to recreate this particular page at will, then I recommend putting the code that draws it into a function, then calling that function as needed.

If you want to be able to record "modified" versions of the screen (eg, with some fields filled in), clear the display (in order to eg draw something else) and then later restore those modified versions, things get a bit more complicated.

If neither of these are your goal, please elaborate as to what your desired result is.
logsys #4
Posted 22 February 2014 - 06:57 AM
If you want to be able to record "modified" versions of the screen (eg, with some fields filled in), clear the display (in order to eg draw something else) and then later restore those modified versions, things get a bit more complicated.
This is what I am looking for, although I want to restore the modified version into the screen and also save to a file. from that file, I would print(using a printer) the ID Card for each player. This is getting tricky to me as I try to find the solution.
Edited on 22 February 2014 - 05:57 AM
Bomb Bloke #5
Posted 22 February 2014 - 07:05 AM
A simple way to do it is with a table. Write your own "printing" functions such that everything gets recorded into that, then should you later wish to restore from it, simply loop through what's inside.

How familiar are you with tables and string editing?
logsys #6
Posted 22 February 2014 - 07:08 AM
A simple way to do it is with a table. Write your own "printing" functions such that everything gets recorded into that, then should you later wish to restore from it, simply loop through what's inside.

How familiar are you with tables and string editing?
A bit, but my problem is to get that region(Top Left Corner(1,1) Bottom Right Corner(26,16)) to be saved into a table/file.
MKlegoman357 #7
Posted 22 February 2014 - 07:32 AM
So basically you want to make a program with which you could register users, be able to save them and print their information onto a paper? I've done exactly that kind of program. What I did was save all information about users into a table so it was pretty easy to manage their info. I kept that table serialized and saved in a file. That table looked like this:


local users = {
["Username1"] = {
name = "Jack",
age = 15,
rank = "admin",
etc...
},

["Username2"] = {
etc..
}
}

Using that kind of table it was pretty easy to deal with. To get age of specific user you get it from that table:


print(users["Username"].age)

To get all of the users from that table you can use a for loop with pairs:


for name, info in pairs(users) do
  print(name .. "'s real name is " .. info.name)
end

Hope that helps a little :D/>
logsys #8
Posted 22 February 2014 - 07:38 AM
So basically you want to make a program with which you could register users, be able to save them and print their information onto a paper? I've done exactly that kind of program. What I did was save all information about users into a table so it was pretty easy to manage their info. I kept that table serialized and saved in a file. That table looked like this:


local users = {
["Username1"] = {
name = "Jack",
age = 15,
rank = "admin",
etc...
},

["Username2"] = {
etc..
}
}

Using that kind of table it was pretty easy to deal with. To get age of specific user you get it from that table:


print(users["Username"].age)

To get all of the users from that table you can use a for loop with pairs:


for name, info in pairs(users) do
  print(name .. "'s real name is " .. info.name)
end

Hope that helps a little :D/>
The way you shown that is really easy, but I have that structure:

I don't need it to print really, its just a way to get easy. My problem is that I will print with that structure, and I would like to replace the spaces with the characters, like it happeans when I use read() to write after that
Is there a possible way to do that?
The info you gave me was really helpful
Bomb Bloke #9
Posted 22 February 2014 - 08:11 AM
Say you wanted to store everything you print into a table. You'd make a function along these lines:

local buffer = {}

local function bufferPrint(text)
	local curx,cury = term.getCursorPos()
	
	if buffer[cury] then                  -- If we've already got some text stored for this line, then...
		if #buffer[cury] < curx then  -- If that saved text doesn't reach the current column, then...
			buffer[cury] = buffer[cury]..string.rep(" ",curx-#buffer[cury]-1)..text
		else                          -- Otherwise the saved text must reach the current column, perhaps exceeding the new text length.
			buffer[cury] = buffer[cury]:sub(1,curx-1)..text..buffer[cury]:sub(curx+#text,#buffer[cury])
		end
	else  -- There's no text in the buffer for this line.
		buffer[cury] = string.rep(" ",curx-1)..text
	end
	
	term.write(text)
	term.setCursorPos(1,cury+1)
end

There are a few ways I can think of off the top of my head that'll break this (scrolling for eg), and I haven't tested it (so don't be surprised if it's buggy), but hopefully it at least gets the general idea across. You could really devote an entire API to doing this properly (eg, handling colour, multiple buffered pages, word-wrap and scrolling, maybe making the function accept co-ords so you don't ever have to call "term.setCursorPos()" separately, etc…).

A few points you may not be familiar with:

"if buffer[cury] then" will treat "buffer[cury]" as "true" if it has a value, or false if it doesn't.

"#buffer[cury]" gets the length of whatever text is in "buffer[cury]".

"string.rep(" ",x)" returns a string which consists of x amount of spaces (it repeats a given string however many times - a space, in this case).

"buffer[cury]:sub(x,y)" returns a sub-string of buffer[cury], starting at character x and ending at character y. So if "buffer[cury]" contains the string "cabbage", and you get "buffer[cury]:sub(4,6)", the result is a string stating "bag".

If you're not familiar with any of the "term" functions, I recommend reviewing the appropriate wiki articles.

Anyway, say you use this function to draw your display (using "bufferPrint" instead of regular "print"), then go off and use regular writing functions for anything you don't want saved. You can then later restore what you buffered like this:

local function restoreBuffer()
	term.clear()
	
	for i=1,table.maxn(buffer) do  -- "table.maxn(buffer)" returns the highest index number in the "buffer" table.
		if buffer[i] then
			term.setCursorPos(1,i)
			term.write(buffer[i])
		end
	end
end

Or write it to a file using something like this:

local function saveBuffer(fileName)
	local myFile = fs.open(fileName,"w")
	
	for i=1,table.maxn(buffer) do
		if buffer[i] then
			myFile.writeLine(buffer[i])
		else
			myFile.writeLine("")
		end
	end
	
	myFile.close()
end
logsys #10
Posted 22 February 2014 - 08:42 AM
I guess I understood, I will try and then I will tell you how it went. Thanks for the help
MKlegoman357 #11
Posted 22 February 2014 - 08:45 AM
Why not use all the info from my table structure to write all the data to a file?


local width = 26
local username = "User"
local user = users[username]
local file = fs.open(username, "w")

file.writeLine(string.rep("-", width))
file.writeLine("|" .. string.rep(" ", width - 2) .. "|")

local function writeVariable (varName, var) --// A function which will automatically format variables
  local s = ("| " .. varName .. ": " .. var):sub(1, width - 1)

  file.writeLine(s .. string.rep(" ", 26 - #s + 1) .. "|")
end

writeVariable("Name", user.name)
writeVariable("Rank", user.rank)

file.writeLine("|" .. string.rep(" ", width - 2) .. "|")
file.writeLine(string.rep("-", width))

file.close()
Edited on 22 February 2014 - 07:46 AM
logsys #12
Posted 22 February 2014 - 08:53 AM
So, I have my ID Card pattern stored in a text file, if I print using infoData:

write(infoData[1])
write(infoData[2])
--it continues until data[16]
it works like this, but with your bufferPrint it doesn't. it gives me: "attempt to concatenate string and table"
how can I fix this?

Why not use all the info from my table structure to write all the data to a file?


local width = 26
local username = "User"
local user = users[username]
local file = fs.open(username, "w")

file.writeLine(string.rep("-", width))
file.writeLine("|" .. string.rep(" ", width - 2) .. "|")

local function writeVariable (varName, var) --// A function which will automatically format variables
  local s = ("| " .. varName .. ": " .. var):sub(1, width - 1)

  file.writeLine(s .. string.rep(" ", 26 - #s + 1) .. "|")
end

writeVariable("Name", user.name)
writeVariable("Rank", user.rank)

file.writeLine("|" .. string.rep(" ", width - 2) .. "|")
file.writeLine(string.rep("-", width))

file.close()
I want to print that into paper, so the players can show it to the staff to identify themselves, so I guess that wouldn't work right
EDIT: I also have a design for it to be, not just words written at the paper
Edited on 22 February 2014 - 07:58 AM
logsys #13
Posted 22 February 2014 - 09:07 AM
Just diagnosed now:

buffer[cury] = string.rep(" ",curx-1)..text
This is the line that is causing problems… And I don't know why
MKlegoman357 #14
Posted 22 February 2014 - 09:14 AM
My given code would write data into a format you gave in a screenshot, with those borders and everything. You could make it print onto a paper with just a few modifications:


local width = 26
local username = "User"
local user = users[username]
local file = fs.open(username, "w")
local printer = peripheral.wrap("printer side")

printer.startPage()

local function writeLine (text) --// A function that will write to the screen, file and a paper
  print(text)

  file.writeLine(text)

  printer.write(text)
  printer.setCursorPos(1, ({printer.getCursorPos()})[2] + 1)
end

writeLine(string.rep("-", width))
writeLine("|" .. string.rep(" ", width - 2) .. "|")

local function writeVariable (varName, var) --// A function which will automatically format variables
  local s = ("| " .. varName .. ": " .. var):sub(1, width - 1)

  writeLine(s .. string.rep(" ", 26 - #s + 1) .. "|")
end

writeVariable("Name", user.name)
writeVariable("Rank", user.rank)

writeLine("|" .. string.rep(" ", width - 2) .. "|")
writeLine(string.rep("-", width))

file.close()
printer.endPage()

A little explanation on '({printer.getCursorPos()})[2]':

I used that to quickly get the current cursor's y position of the paper.

1. {printer.getCursorPos()} - getting cursor position and inserting returned variables (x, y) into a table.
2. ({printer.getCursorPos()}) - we need those parenthesis because you can't just do {"One", "Two"}[2].
3. ({printer.getCursorPos()})[2] - getting the second variable which is y position of the cursor.
Edited on 22 February 2014 - 08:15 AM
CometWolf #15
Posted 22 February 2014 - 09:18 AM
Just diagnosed now:

buffer[cury] = string.rep(" ",curx-1)..text
This is the line that is causing problems… And I don't know why
Im guessing you're reffering to bomb's code.
So the problem is pretty obvious, "attempt to concatenate string and table" means you can't combine a string and a table. Since string.rep(" ",cursx-1) is obviously a string, the problem is the variable text. text being the variable you yourself are passing to the function. Use it the same way you used write.

bufferPrint(infoData[1])
logsys #16
Posted 22 February 2014 - 09:18 AM
I thought it wouldn't print what was in the screen. Sorry. So, with that, I will print everything in the screen? or just until the x character I want?
logsys #17
Posted 22 February 2014 - 09:33 AM
MKlegoman357, I don't know how u mean to use it. I have the screen, right? I want the printer to scan that region of the screen and print it, cause im getting error when only using your writeline function: a nil value. Also, I am on craftos 1.5, can that be the problem?
MKlegoman357 #18
Posted 22 February 2014 - 09:36 AM
With my example it would work just like a normal print function for terminal, it would just write lines of text to the file and it would print as much lines of text as the height of the paper. With Bomb Bloke example it could be setup to work like a normal print function.

…or just until the x character I want?

My function 'writeLine' would work like a normal 'print' function on a terminal + it would write to a file and a paper.

What's the full error? You do realize that you have to wrap the printer and open a file before you can use that function?
logsys #19
Posted 22 February 2014 - 09:37 AM
With my example it would work just like a normal print function for terminal, it would just write lines of text to the file and it would print as much lines of text as the height of the paper. With Bomb Bloke example it could be setup to work like a normal print function.

…or just until the x character I want?

My function 'writeLine' would work like a normal 'print' function on a terminal + it would write to a file and a paper.

What's the full error? You do realize that you have to wrap the printer and open a file before you can use that function?
I have a printer on its side, how do I use the program? I have to open it manually or just the function? Can u give me a text tutorial?
MKlegoman357 #20
Posted 22 February 2014 - 09:43 AM
Wow ^^^^

Somehow I edited my previous post and didn't make 'Edited by' line O_O

This line here:
What's the full error? You do realize that you have to wrap the printer and open a file before you can use that function?

was added after I posted the above post.


...

local file = fs.open(username, "w") --// open a file in which you want to save your screen
local printer = peripheral.wrap("printer side") --// Change that to your printer side

...

Note that my example code uses my table called 'users' which was explained earlier.

Also, this text right here is the second edit of my post without 'Edited by' line O_O

EDIT: test

Final test, don't mind these.
Edited on 22 February 2014 - 08:43 AM
logsys #21
Posted 22 February 2014 - 09:45 AM
Now I get expected string, string

and its at fs.open(username,"w")

and now its at printer.write(text) with page not started
MKlegoman357 #22
Posted 22 February 2014 - 09:52 AM
Now I get expected string, string

and its at fs.open(username,"w")

The 'username' variable doesn't exist or is not set to anything

and now its at printer.write(text) with page not started

My bad, it's 'printer.newPage()' not 'printer.startPage()'. I don't use printers often :P/>

Also note that All of my code was written on forums and is not tested.
logsys #23
Posted 22 February 2014 - 09:54 AM
yh, ik its not tested, but its not printing the way I want it to
is it because its a table and it must be a plain string or what?
MKlegoman357 #24
Posted 22 February 2014 - 10:14 AM
yh, ik its not tested, but its not printing the way I want it to
is it because its a table and it must be a plain string or what?

What table? My example code should work the only difference is that you have to define 'users' table first with the user you want in that table.
logsys #25
Posted 22 February 2014 - 10:19 AM
You have a computercraft emulator?
MKlegoman357 #26
Posted 22 February 2014 - 10:20 AM
What do you mean? I can get one easily.
logsys #27
Posted 22 February 2014 - 10:25 AM
forget, i will try getting the program to work by myself, then I will tell u how it went k?
MKlegoman357 #28
Posted 22 February 2014 - 10:25 AM
Ok, here's the full example. Just place a computer and put a printer on the right side of the computer. Don't forget to load that printer with ink and paper.


local users = {
  ["User"] = {
    name = "Tom",
    rank = "admin"
  }
}

local width = 26
local username = "User"
local user = users[username]
local file = fs.open(username, "w")
local printer = peripheral.wrap("right") --// Assuming you have a printer on the right side of the computer

printer.newPage()

local function writeLine (text) --// A function that will write to the screen, file and a paper
  print(text)

  file.writeLine(text)

  printer.write(text)
  printer.setCursorPos(1, ({printer.getCursorPos()})[2] + 1)
end

writeLine(string.rep("-", width))
writeLine("|" .. string.rep(" ", width - 2) .. "|")

local function writeVariable (varName, var) --// A function which will automatically format variables
  local s = ("| " .. varName .. ": " .. var):sub(1, width - 1)

  writeLine(s .. string.rep(" ", width - #s - 1) .. "|")
end

writeVariable("Name", user.name)
writeVariable("Rank", user.rank)

writeLine("|" .. string.rep(" ", width - 2) .. "|")
writeLine(string.rep("-", width))

file.close()
printer.endPage()

EDIT: Fixed the code, it can be found here.
Edited on 22 February 2014 - 09:37 AM
logsys #29
Posted 22 February 2014 - 12:54 PM
I will try this, but I made it better: Removed the right borders and made it 2 pages with a SHA-1 Security Hash. As I am making a server that the players vote for a guy to be below owner, I need a way to ensure players don't cheat(offline mode server, the other owner isn't premium). Thanks for all your help. I will vote for your posts to "pay" for your help.