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

PHP screenshot generator v2 now with color!

Started by Jan, 07 May 2013 - 04:01 PM
Jan #1
Posted 07 May 2013 - 06:01 PM
Introduction
Today I made a screenshot generator using PHP and GD (an image libarary)
Currently you send the text, and the monitor width and height to my php script on my website, and then it generates an image with it.
It doesnt support color yet.

Screenshot of paint:


Long link:

http://janvanrosmalen.com/ccrender/color/51/19/+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++XX+++++++++++++++++++++++++++++++++++++++++++++++++++%5BSave%5D+Exit++++++++++++++++++++++++++++++++++++++++/888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888800888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888400004000000888888888888888888888888888888888888888/000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000055000000000000000000000000000000000000000000000000066000000000fff0fffffffffffff00000000000000000000000770000fff0f00000000ffff00000ffffff0000000000000000088fff000000000000fff00ff000000000ffff0000000000000099f00000000000000f00000f0000000000000ff000000000000aaf000000000000000fffffff00000000ffffff000000000000bbff00000000000fffff000fffffff0f0000000000000000000cc0fff00000000f0000ff00000ff000f0000000ff0000000000dd000fffff0000f00000ffff0f0fff000000000000000000000ee0000000fffffffff0000ff00000ff00000000000000000000ff0000000000000000ffffffffffffff0fff0fffff0000000000000000000000000000ffff0000000ff0000000000000000000f0888888888888888888888888888888888888888888888888888/13/19/0/8/false/screenshot.png
Now you are probably thinking: how did he generate the link?

How to make a screenshot
1. Install the lua program below
2. Run the screenshot program
3. Run the program you want to take a screenshot from
4. Press f1
5. leave CC, and open your computer files
6. Open screen.txt and copy the link
7. On these forums, click on Image, and paste the link
8. Done!



Lua program v2
It uses gophers buffer redirect API:
http://www.computerc...__hl__gopheratl

Lua code v2:
http://pastebin.com/BCbdfzsY

http://pastebin.com/uPJ066tJ old

pastebin get BCbdfzsY screenshot

Spoiler

-- Version 2
term.clear()
term.setCursorPos(1,1)

-- Uses Gopher's redirect buffer api v1.2
-- http://www.computercraft.info/forums2/index.php?/topic/5130-gophers-apis-new-ggui-beta-goroutine-redirect-ctrlkeys/page__hl__gopheratl
local trueCursor={term.getCursorPos()}

local redirectBufferBase = {
	write=
	  function(buffer,...)
		local cy=buffer.curY
		if cy>0 and cy<=buffer.height then
		  local text=table.concat({...}," ")
		  local cx=buffer.curX
		  local px, py
		  if buffer.isActive and not buffer.cursorBlink then
			term.native.setCursorPos(cx+buffer.scrX, cy+buffer.scrY)
		  end
		  for i=1,#text do
			if cx<=buffer.width then
			  local curCell=buffer[cy][cx]
			  local char,textColor,backgroundColor=string.char(text:byte(i)),buffer.textColor,buffer.backgroundColor
			  if buffer[cy].isDirty or curCell.char~=char or curCell.textColor~=textColor or curCell.backgroundColor~=backgroundColor then
				buffer[cy][cx].char=char
				buffer[cy][cx].textColor=textColor
				buffer[cy][cx].backgroundColor=backgroundColor
				buffer[cy].isDirty=true
			  end
			end
			cx=cx+1
		  end
		  buffer.curX=cx
		  if buffer.isActive then
			buffer.drawDirty()
			if not buffer.cursorBlink then
			  trueCursor={cx+buffer.scrX-1,cy+buffer.scrY-1}
			  term.native.setCursorPos(unpack(trueCursor))
			end
		  end
		end
	  end,
	
	setCursorPos=
	  function(buffer,x,y)
		buffer.curX=math.floor(x)
		buffer.curY=math.floor(y)
		if buffer.isActive and buffer.cursorBlink then
		  term.native.setCursorPos(x+buffer.scrX-1,y+buffer.scrY-1)
		  trueCursor={x+buffer.scrX-1,y+buffer.scrY-1}
		end
	  end,
	
	getCursorPos=
	  function(buffer)
		return buffer.curX,buffer.curY
	  end,
	
	scroll=
	  function(buffer,offset)
		for j=1,offset do
		  local temp=table.remove(buffer,1)
		  table.insert(buffer,temp)
		  for i=1,#temp do
			temp[i].char=" "
			temp[i].textColor=buffer.textColor
			temp[i].backgroundColor=buffer.backgroundColor
		  end
		end
		if buffer.isActive then
		  term.redirect(term.native)
		  buffer.blit()
		  term.restore()
		end
	  end,
	
	isColor=
	  function(buffer)
		return buffer._isColor
	  end,
	
	isColour=
	  function(buffer)
		return buffer._isColor
	  end,
	
	clear=
	  function(buffer)
		for y=1,buffer.height do
		  for x=1,buffer.width do
			buffer[y][x]={char=" ",textColor=buffer.textColor,backgroundColor=buffer.backgroundColor}
		  end
		end
		if buffer.isActive then
		  term.redirect(term.native)
		  buffer.blit()
		  term.restore()
		end
	  end,
	
	clearLine=
	  function(buffer)
		local line=buffer[buffer.curY]
		local fg,bg = buffer.textColor, buffer.backgroundColor
		for x=1,buffer.width do
		  line[x]={char=" ",textColor=fg,backgroundColor=bg}
		end
		buffer[buffer.curY].isDirty=true
		if buffer.isActive then
		  buffer.drawDirty()
		end
	  end,
	
	setCursorBlink=
	  function(buffer,onoff)
		buffer.cursorBlink=onoff
		if buffer.isActive then
		  term.native.setCursorBlink(onoff)
		  if onoff then
			term.native.setCursorPos(buffer.curX,buffer.curY)
			trueCursor={buffer.curX,buffer.curY}
		  end
		end
	  end,
	
	getSize=
	  function(buffer)
		return buffer.width, buffer.height
	  end,
	
	setTextColor=
	  function(buffer,color)
		buffer.textColor=color
		if buffer.isActive then
		  if term.native.isColor() or color==colors.black or color==colors.white then
			term.native.setTextColor(color)
		  end
		end
	  end,
	
	setTextColour=
	  function(buffer,color)
		buffer.textColor=color
		if buffer.isActive then
		  if term.native.isColor() or color==colors.black or color==colors.white then
			term.native.setTextColor(color)
		  end
		end
	  end,
	
	setBackgroundColor=
	  function(buffer,color)
		buffer.backgroundColor=color
		if buffer.isActive then
		  if term.native.isColor() or color==colors.black or color==colors.white then
		term.native.setBackgroundColor(color)
		  end
		end
	  end,
	
	setBackgroundColour=
	  function(buffer,color)
		buffer.backgroundColor=color
		if buffer.isActive then
		  if term.native.isColor() or color==colors.black or color==colors.white then
		term.native.setBackgroundColor(color)
		  end
		end
	  end,
  
	resize=
	  function(buffer,width,height)
		if buffer.width~=width or buffer.height~=height then
		  local fg, bg=buffer.textColor, buffer.backgroundColor
		  if width>buffer.width then
			for y=1,buffer.height do
			  for x=#buffer[y]+1,width do
				buffer[y][x]={char=" ",textColor=fg,backgroundColor=bg}
			  end
			end
		  end

		  if height>buffer.height then
			local w=width>buffer.width and width or buffer.width
			for y=#buffer+1,height do
			  local row={}		
			  for x=1,width do
				row[x]={char=" ",textColor=fg,backgroundColor=bg}
			  end
			  buffer[y]=row
			end
		  end
		  buffer.width=width
		  buffer.height=height
		end
	  end,
	
	blit=
	  function(buffer,sx,sy,dx, dy, width,height)
		sx=sx or 1
		sy=sy or 1
		dx=dx or buffer.scrX
		dy=dy or buffer.scrY
		width=width or buffer.width
		height=height or buffer.height
	  
		local h=sy+height>buffer.height and buffer.height-sy or height-1
		for y=0,h do
		  local row=buffer[sy+y]
		  local x=0
		  local cell=row[sx]
		  local fg,bg=cell.textColor,cell.backgroundColor
		  local str=""
		  local tx=x
		  while true do
			str=str..cell.char
			x=x+1
			if x==width or sx+x>buffer.width then
			  break
			end
			cell=row[sx+x]
			if cell.textColor~=fg or cell.backgroundColor~=bg then
			  --write
			  term.setCursorPos(dx+tx,dy+y)
			  term.setTextColor(fg)
			  term.setBackgroundColor(bg)
			  term.write(str)
			  str=""
			  tx=x
			  fg=cell.textColor
			  bg=cell.backgroundColor			
			end
		  end
		  term.setCursorPos(dx+tx,dy+y)
		  term.setTextColor(fg)
		  term.setBackgroundColor(bg)
		  term.write(str)
		end
	  end,
	
	drawDirty =
	  function(buffer)
		term.redirect(term.native)
		for y=1,buffer.height do
		  if buffer[y].isDirty then
			term.redirect(term.native)
			buffer.blit(1,y,buffer.scrX,buffer.scrY+y-1,buffer.width,buffer.height)
			term.restore()
			buffer[y].isDirty=false
		  end
		end
		term.restore()
	  end,
	
	makeActive =
	  function(buffer,posX, posY)
		posX=posX or 1
		posY=posY or 1
		buffer.scrX=posX
		buffer.scrY=posY
		term.redirect(term.native)
		buffer.blit(1,1,posX,posY,buffer.width,buffer.height)
		term.setCursorPos(buffer.curX,buffer.curY)
		term.setCursorBlink(buffer.cursorBlink)
		term.setTextColor(buffer.textColor)
		term.setBackgroundColor(buffer.backgroundColor)
		buffer.isActive=true
		term.restore()
	  end,
	
	isBuffer = true,
  
  }
  

function createRedirectBuffer(width,height,fg,bg,isColor)
   bg=bg or colors.black
   fg=fg or colors.white
   isColor=isColor~=nil and isColor or term.isColor()
   local buffer={}
  
   do
	 local w,h=term.getSize()
	 width,height=width or w,height or h
   end
  
   for y=1,height do
	 local row={}
	 for x=1,width do
	   row[x]={char=" ",textColor=fg,backgroundColor=bg}
	 end
	 buffer[y]=row
   end
   buffer.scrX=1
   buffer.scrY=1
   buffer.width=width
   buffer.height=height
   buffer.cursorBlink=false
   buffer.textColor=fg
   buffer.backgroundColor=bg
   buffer._isColor=isColor
   buffer.curX=1
   buffer.curY=1
  
   local meta={}
   local function wrap(f,o)
	 return function(...)
		 return f(o,...)
	   end
   end
   for k,v in pairs(redirectBufferBase) do
	 if type(v)=="function" then
	   meta[k]=wrap(v,buffer)
	 else
	   meta[k]=v
	 end
   end
   setmetatable(buffer,{__index=meta})
   return buffer
end
local w,h = term.getSize()
local buff = createRedirectBuffer(w,h,colors.white,colors.black,true)
term.redirect(buff)
buff.makeActive(1,1)
function screenshot()
  local function c(num) --color conversion
	return string.format("%x",math.log(num)/math.log(2))
  end
  local text = ""
  local fore = ""
  local back = ""
  for y,row in ipairs(buff) do
	for x,char in ipairs(row) do
	  text=text..char.char
	  fore=fore..c(char.textColor)
	  back=back..c(char.backgroundColor)
	end
  end
  local file = io.open("screen.txt","a")
  local url = "\nhttp://janvanrosmalen.com/ccrender/color/"
  local function add(text)
	url = url..textutils.urlEncode(tostring(text)).."/"
  end
  add(w) add(h) add(text) add(fore) add(back) add(buff.curX) add(buff.curY)
  add(c(buff.textColor)) add(c(buff.backgroundColor)) add(buff.cursorBlink)
  file:write(url.."screenshot.png")
  file:close()
end

local roll=true
function go()
  print("Press f1 to make a screenshot.")
  print("Type exit to leave screenshot mode")
  shell.run("rom/programs/shell")
  roll=false
end
local route = coroutine.create(go)
os.queueEvent("derp")
while roll do
  local evt = {os.pullEventRaw()}
  if (evt[1]=="key") and (evt[2]==keys.f1) then
	screenshot()
  end
  coroutine.resume(route,unpack(evt))
end
term.restore()
term.clear()
term.setCursorPos(1,1)
print("Left screenshot mode")

For server hosts
Here are the files required to run the generator on your own site
Here is the PHP code (screenshot.php):
Spoiler

<?php
$mcwool = array();
$mcwool[0] = array(255,255,255); // White
$mcwool[1] = array(235,136,68);  // Orange
$mcwool[2] = array(195,84,205);  // Magenta
$mcwool[3] = array(102,137,211); // Light blue
$mcwool[4] = array(222,222,108); // Yellow
$mcwool[5] = array(65,205,52); // Lime
$mcwool[6] = array(216,129,152);  // Pink
$mcwool[7] = array(67,67,67);  // Gray
$mcwool[8] = array(153,153,153);  // Light gray
$mcwool[9] = array(40,118,151);   // Cyan
$mcwool[10] = array(123,47,190);   // Purple
$mcwool[11] = array(37,49,146); // Blue
$mcwool[12] = array(81,48,26);  // Brown
$mcwool[13] = array(59,81,26);  // Green
$mcwool[14] = array(179,49,44); // Red
$mcwool[15] = array(0,0,0);  // Black
function between($what,$l,$r){
  $m = (int) $what;
  if ($m<$l) {
    return $l;
  };
  if ($m>$r) {
    return $r;
  };
  return $m;
};

header("Content-type: image/png");
$width = between($_GET['w'],1,100);
$height = between($_GET['h'],1,100);
$string = $_GET['t'];
$fore = $_GET['f'];
$back = $_GET['b'];
$bbg = false;
if ($back==""){
$bbg=true;
};
$cx = between($_GET['x'],1,100);
$cy = between($_GET['y'],1,100);
$cfore = $_GET['m'];
$cback = $_GET['n'];
$im	 = imagecreatetruecolor($width*6+1, $height*9+1);

$getcol = array();
for ($i=0;$i<16;$i++) {
$getcol[$i] = imagecolorallocate($im,$mcwool[$i][0],$mcwool[$i][1],$mcwool[$i][2]);
};
for ($y=0;$y<$height;$y++){
  for ($x=0;$x<$width;$x++){
    if ($bbg==false){
	  imagefilledrectangle ($im,$x*6,$y*9,$x*6+6,$y*9+9, $getcol[(int) hexdec($back[$y*$width+$x])]);   
    };
    $letter = (string) $string[$y*$width+$x];
    $data = imageftbbox (6,0,"Minecraftia",$letter);
    imagefttext($im,6,0,$x*6+(5-$data[2])/2,$y*9+7,$getcol[(int) hexdec($fore[$y*$width+$x])],"Minecraftia",$letter);
  }
}
imagestring($im,3,1,1,(string) $cblink,$getcol[1]);
imagefilledrectangle ($im,$cx*6-6,$cy*9-2,$cx*6-2,$cy*9-2, $getcol[(int) hexdec($cfore)]);   
imagepng($im);
imagedestroy($im);
?>

Here is the .htaccess (for magic links)
Spoiler

Options +FollowSymlinks
RewriteEngine on
RewriteRule ^color/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+).png screenshot.php?w=$1&amp;h=$2&amp;t=$3&amp;f=$4&amp;b=$5&amp;x=$6&amp;y=$7&amp;m=$8&amp;n=$9 [NC]
RewriteRule ^trick/([^/]+)/([^/]+)/([^/]+).png screenshot.php?w=$1&amp;h=$2&amp;t=$3 [NC]
DirectoryIndex screenshot.php


TODO
- color support
- workaround to let images work on these forums (priority!)
fixed! Now I need to update the lua program to produce links using the 'trick'.
- database. After making a screenshot, it will be send via http API.
then a shorter url is returned to minecraft. (will be hard, and needs to be done very secure, to prevent spam and code execution of SQL)

I will not make this probably
- Fix color bugs
Fixed, thanks to Gravity
- Work for non-colored terminals (next update)

License
You are free to use this program, edit it, or host it. You may also integrate it in your OS or whatever you want.
I would like you to post a link to this thread if you use screenshots generated with this :)/>

If you have any improvements, please post them. Have fun with the screenshots!
D3matt #2
Posted 07 May 2013 - 06:39 PM
Awesome!

You should be able to use a .png extension for the file and still have it work. Just have it ignore .php at the end of the string and add it that way.
Jan #3
Posted 07 May 2013 - 06:51 PM
Awesome!

You should be able to use a .png extension for the file and still have it work. Just have it ignore .php at the end of the string and add it that way.
Yes i found a way using .htaccess to do so.
http://corz.org/serv/tricks/htaccess2.php
It transforms:
trick/51/19/text.png
to:
screenshot.php?w=51&amp;h=19&amp;t=text

Options +FollowSymlinks
RewriteEngine on
RewriteRule ^trick/([^/]+)/([^/]+)/([^/]+).png screenshot.php?w=$1&amp;h=$2&amp;t=$3 [NC]
DirectoryIndex screenshot.php
i'll update the lua program tomorrow I think
D3matt #4
Posted 07 May 2013 - 07:19 PM
Ah yes, htaccess. Wonderous thing.
Jan #5
Posted 08 May 2013 - 08:14 AM
Large update: added workaround for the forums, color support, and cursor rendering (it will always be rendered, even if blink is off)
superaxander #6
Posted 08 May 2013 - 08:17 AM
Nice!
Jan #7
Posted 08 May 2013 - 09:43 AM
There appears to be a bug when using non-colored displays. It directly leaves the program…
To fix this,line 238 should be:
local buff = createRedirectBuffer(w,h,colors.white,colors.black)
instead of:
local buff = createRedirectBuffer(w,h,colors.white,colors.black,true)

there are probably other bugs so I'll wait with updating the program
GravityScore #8
Posted 08 May 2013 - 09:49 AM
If you know the (RGB) values (decimal) of CC, please post them, thanks

Here you go, already formatted as Java strings, in RGB form, separated by commas:

colors = new String[16];
colors[15] = "255,255,255"; // White
colors[14] = "235,136,68";  // Orange
colors[13] = "195,84,205";  // Magenta
colors[12] = "102,137,211"; // Light blue
colors[11] = "222,222,108"; // Yellow
colors[10] = "65,205,52"; // Lime
colors[9] = "216,129,152";  // Pink
colors[8] = "67,67,67";  // Gray
colors[7] = "153,153,153";  // Light gray
colors[6] = "40,118,151";   // Cyan
colors[5] = "123,47,190";   // Purple
colors[4] = "37,49,146"; // Blue
colors[3] = "81,48,26";  // Brown
colors[2] = "59,81,26";  // Green
colors[1] = "179,49,44"; // Red
colors[0] = "0,0,0";  // Black

Not in decimal sorry, but you can just input these values, and divide them by 255.

EDIT: also, the font you're using isn't the same as CC's. CC uses the default Minecraft font, and a replica can be found here.
Jan #9
Posted 08 May 2013 - 09:52 AM
If you know the (RGB) values (decimal) of CC, please post them, thanks

Here you go, already formatted as Java strings, in RGB form, separated by commas:


colors = new String[16];
colors[15] = "255,255,255"; // White
colors[14] = "235,136,68";  // Orange
colors[13] = "195,84,205";  // Magenta
colors[12] = "102,137,211"; // Light blue
colors[11] = "222,222,108"; // Yellow
colors[10] = "65,205,52"; // Lime
colors[9] = "216,129,152";  // Pink
colors[8] = "67,67,67";  // Gray
colors[7] = "153,153,153";  // Light gray
colors[6] = "40,118,151";   // Cyan
colors[5] = "123,47,190";   // Purple
colors[4] = "37,49,146"; // Blue
colors[3] = "81,48,26";  // Brown
colors[2] = "59,81,26";  // Green
colors[1] = "179,49,44"; // Red
colors[0] = "0,0,0";  // Black

Not in decimal sorry, but you can just input these values, and divide them by 255.
Thank you very much! I am now inserting them in the PHP script.
Oh and with decimal I meant it like 'not in hexadecimal'
GravityScore #10
Posted 08 May 2013 - 09:54 AM
Oh and with decimal I meant it like 'not in hexadecimal'

Oh I see :P/> Also, read the edit about fonts :P/>
Jan #11
Posted 08 May 2013 - 10:28 AM
Oh and with decimal I meant it like 'not in hexadecimal'

Oh I see :P/> Also, read the edit about fonts :P/>
Good idea about the fonts, I implemented it.
Now I need to make it 'pixel perfect'. Also, some letters arent centered :/
EDIT: going to fix it…
diegodan1893 #12
Posted 08 May 2013 - 01:51 PM
Nice! I was looking for something like this for my program.

Suggestion: can you increase the image size to be the same as ComputerCraft term?
Left4Cake #13
Posted 08 May 2013 - 02:00 PM
Jan #14
Posted 08 May 2013 - 03:05 PM
Nice! I was looking for something like this for my program.

Suggestion: can you increase the image size to be the same as ComputerCraft term?
Thanks :)/>
The size of the image is actually the same size as the monitor in-game (when you make the minecraftwindow smaller)
You probably meant scaling?
PixelToast #15
Posted 08 May 2013 - 03:11 PM
oh god long urls, y u no base64
nice rendering code :3