#!/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"); } ?>