#!/usr/bin/env php
>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
if(PHP_SAPI!=='cli'){die('
Commandline only!');}
// Launch in BG with system('php genpreviews.php > /dev/null &')
chdir(dirname($_SERVER['SCRIPT_FILENAME']));
// Make sure only one instance is running at a time
$lock=fopen('files', 'r');
if(!flock($lock, LOCK_EX|LOCK_NB)){die("Lock failed");}
include_once('db.php');
include_once('config.php');
include_once('files.php');
mkdir(TMPDIR, 755);
$res=mysqli_query($db, 'select distinct lower(substring_index(name,".",-1)) as type, hash from files');
while($row=mysqli_fetch_assoc($res))
{
$file=getfilepath($row['hash'], true);
// Preview image
if(file_exists($file.'.png')){continue;}
$img=false;
switch($row['type'])
{
// Scale down images to more suitable sizes
case 'png': if(!$img){$img=imagecreatefrompng($file);}
case 'jpg':
case 'jpeg': if(!$img){$img=imagecreatefromjpeg($file);}
case 'gif': if(!$img){$img=imagecreatefromgif($file);}
if(!$img){break;} // Failed to load image
$x=imagesx($img);
$y=imagesy($img);
if($x/PREVIEW_SIZE[0]<$y/PREVIEW_SIZE[1]) // Maintain aspect ratio
{
$ox=$x*PREVIEW_SIZE[1]/$y;
$oy=PREVIEW_SIZE[1];
}else{
$ox=PREVIEW_SIZE[0];
$oy=$y*PREVIEW_SIZE[0]/$x;
}
$out=imagecreatetruecolor($ox, $oy);
imagecopyresampled($out, $img, 0, 0, 0, 0, $ox, $oy, $x, $y);
imagepng($out, $file.'.png');
imagedestroy($img);
imagedestroy($out);
break;
case 'blend':
case '3mf':
case 'x3d':
case 'obj':
case 'stl':
// Convert to STL for the next step (even for stl for bin->ascii)
copy($file, TMPDIR.'/thingsharepreview_orig.'.$row['type']);
system('assimp export '.escapeshellarg(TMPDIR.'/thingsharepreview_orig.'.$row['type']).' '.escapeshellarg(TMPDIR.'/thingsharepreview.stl'));
unlink(TMPDIR.'/thingsharepreview_orig.'.$row['type']);
switch(PREVIEW_RENDERMETHOD)
{
case 'povray':
// Translate STL to Povray (could have used stl2pov for this but it required a lot of tweaking of the output and didn't give us access to useful data like min/max vertex positions)
$min=Array(false,false,false);
$max=Array(false,false,false);
$in=fopen(TMPDIR.'/thingsharepreview.stl', 'r');
$out=fopen(TMPDIR.'/thingsharepreview.pov', 'w');
while($line=fgets($in))
{
if(substr(trim($line), 0, 7)=='vertex ')
{
$vertex=array_slice(explode(' ', trim($line)), 1);
$facet[]=$vertex;
for($i=0; $i<3; ++$i)
{
if($min[$i]===false || $vertex[$i]<$min[$i]){$min[$i]=$vertex[$i];}
if($max[$i]===false || $vertex[$i]>$max[$i]){$max[$i]=$vertex[$i];}
}
}
elseif(substr(trim($line), 0, 6)=='facet ')
{
$facet=Array(); // Start empty
}
elseif(trim($line)=='endfacet')
{
if(count($facet)==3){fwrite($out, " triangle {\n");}
elseif(count($facet)==4){fwrite($out, " square {\n");}
foreach($facet as $vertex)
{
fwrite($out, ' <'.$vertex[0].','.$vertex[1].','.$vertex[2].">\n");
}
fwrite($out, " }\n");
}
elseif(substr(trim($line), 0, 6)=='solid ')
{
fwrite($out, "mesh {\n");
}
}
fclose($f);
$dist=0;
$maxdist=0;
$avg=Array();
for($i=0; $i<3; ++$i)
{
$avg[$i]=($max[$i]+$min[$i])/2;
if($max[$i]-$min[$i]>$maxdist){$maxdist=$max[$i]-$min[$i];}
$dist+=($max[$i]-$min[$i])/3;
}
$dist=($dist+$maxdist)/2; // $dist and $maxdist worked great for different cases, averaging gives us decent enough results for all cases. TODO: An even more accurate method would likely be to convert each vertex coordinate to be in relation to the camera
fwrite($out, " texture {\n");
fwrite($out, ' pigment { color rgb<'.(PREVIEW_COLOR[0]/255).','.(PREVIEW_COLOR[1]/255).','.(PREVIEW_COLOR[2]/255)."> }\n");
fwrite($out, " finish { ambient 0.2 diffuse 0.7 }\n");
fwrite($out, " }\n}\n");
// Scene setup
fwrite($out, "global_settings { ambient_light rgb<1, 1, 1> }\n");
fwrite($out, "background { color rgb<1,1,1> }\n"); // TODO: Configurable background color?
fwrite($out, "camera {\n");
$dist/=1.65;
fwrite($out, ' location <'.($max[0]+$dist).','.($max[1]+$dist).','.($max[2]+$dist).">\n");
fwrite($out, ' look_at <'.$avg[0].','.$avg[1].','.$avg[2].">\n");
fwrite($out, ' right x*'.(PREVIEW_SIZE[0]/PREVIEW_SIZE[1])."\n");
fwrite($out, " sky <0,0,1>\n}\n"); // Set Z vertical
fwrite($out, 'light_source { <'.($max[0]+$dist+10).','.($max[1]+$dist).','.($max[2]+$dist+20).'> color rgb<1, 1, 1> }'); // Light slightly offset from camera to distinguish corners better
// Render using Povray
$tmpfile=escapeshellarg(TMPDIR.'/thingsharepreview.pov');
system('povray +I'.$tmpfile.' +O'.escapeshellarg($file.'.png').' -D +P +W'.(int)PREVIEW_SIZE[0].' +H'.(int)PREVIEW_SIZE[1].' +A0.5');
unlink(TMPDIR.'/thingsharepreview.pov');
break;
case 'openscad': // TODO: Test this code (completely untested so far), looks like we need to rename the file for the import to identify it correctly
$c=sprintf('#%02x%02x%02x', PREVIEW_COLOR[0], PREVIEW_COLOR[1], PREVIEW_COLOR[2]);
copy($file, TMPDIR.'/thingsharepreview.'.$row['type']);
file_put_contents(TMPDIR.'/thingsharepreview.scad', 'color("'.$c.'")import("thingsharepreview.'.str_replace('"', '', $row['type']).'");');
system('openscad --imgsize '.(int)PREVIEW_SIZE[0].','.(int)PREVIEW_SIZE[1].' -o '.escapeshellarg($file.'.png').' '.escapeshellarg(TMPDIR.'/thingsharepreview.scad'));
unlink(TMPDIR.'/thingsharepreview.'.$row['type']);
unlink(TMPDIR.'/thingsharepreview.scad');
break;
}
unlink(TMPDIR.'/thingsharepreview.stl');
break;
}
// TODO: Preview 3D model (x3d)
// print($file.'.'.$row['type']."\n");
}
?>