netrender: refactor thumbnail generation code. New option to generate the thumbnail on the slaves (per slave option, default off). Missing thumbnails are still generated on demand by the master.
This commit is contained in:
@@ -174,7 +174,8 @@ class MRenderFrame(netrender.model.RenderFrame):
|
||||
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
file_pattern = re.compile("/file_([a-zA-Z0-9]+)_([0-9]+)")
|
||||
render_pattern = re.compile("/render_([a-zA-Z0-9]+)_([0-9]+).(exr|jpg)")
|
||||
render_pattern = re.compile("/render_([a-zA-Z0-9]+)_([0-9]+).exr")
|
||||
thumb_pattern = re.compile("/thumb_([a-zA-Z0-9]+)_([0-9]+).jpg")
|
||||
log_pattern = re.compile("/log_([a-zA-Z0-9]+)_([0-9]+).log")
|
||||
reset_pattern = re.compile("/reset(all|)_([a-zA-Z0-9]+)_([0-9]+)")
|
||||
cancel_pattern = re.compile("/cancel_([a-zA-Z0-9]+)")
|
||||
@@ -231,8 +232,6 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
|
||||
job_id = match.groups()[0]
|
||||
frame_number = int(match.groups()[1])
|
||||
|
||||
exr = match.groups()[2] == "exr"
|
||||
|
||||
job = self.server.getJobID(job_id)
|
||||
|
||||
if job:
|
||||
@@ -244,33 +243,11 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
|
||||
elif frame.status == DONE:
|
||||
self.server.stats("", "Sending result to client")
|
||||
|
||||
if exr:
|
||||
f = open(job.save_path + "%04d" % frame_number + ".exr", 'rb')
|
||||
self.send_head(content = "image/x-exr")
|
||||
else:
|
||||
filename = job.save_path + "%04d" % frame_number + ".jpg"
|
||||
|
||||
if not os.path.exists(filename):
|
||||
import bpy
|
||||
sce = bpy.data.scenes[0]
|
||||
sce.render_data.file_format = "JPEG"
|
||||
sce.render_data.quality = 90
|
||||
bpy.ops.image.open(path = job.save_path + "%04d" % frame_number + ".exr")
|
||||
img = bpy.data.images["%04d" % frame_number + ".exr"]
|
||||
img.save(filename, scene = sce)
|
||||
|
||||
try:
|
||||
process = subprocess.Popen(["convert", filename, "-resize", "300x300", filename])
|
||||
process.wait()
|
||||
except:
|
||||
pass
|
||||
|
||||
f = open(filename, 'rb')
|
||||
self.send_head(content = "image/jpeg")
|
||||
|
||||
|
||||
filename = job.save_path + "%04d" % frame_number + ".exr"
|
||||
|
||||
f = open(filename, 'rb')
|
||||
self.send_head(content = "image/x-exr")
|
||||
shutil.copyfileobj(f, self.wfile)
|
||||
|
||||
f.close()
|
||||
elif frame.status == ERROR:
|
||||
self.send_head(http.client.PARTIAL_CONTENT)
|
||||
@@ -284,6 +261,46 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
|
||||
# invalid url
|
||||
self.send_head(http.client.NO_CONTENT)
|
||||
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
elif self.path.startswith("/thumb"):
|
||||
match = thumb_pattern.match(self.path)
|
||||
|
||||
if match:
|
||||
job_id = match.groups()[0]
|
||||
frame_number = int(match.groups()[1])
|
||||
|
||||
job = self.server.getJobID(job_id)
|
||||
|
||||
if job:
|
||||
frame = job[frame_number]
|
||||
|
||||
if frame:
|
||||
if frame.status in (QUEUED, DISPATCHED):
|
||||
self.send_head(http.client.ACCEPTED)
|
||||
elif frame.status == DONE:
|
||||
filename = job.save_path + "%04d" % frame_number + ".exr"
|
||||
|
||||
thumbname = thumbnail(filename)
|
||||
|
||||
if thumbname:
|
||||
f = open(thumbname, 'rb')
|
||||
self.send_head(content = "image/jpeg")
|
||||
shutil.copyfileobj(f, self.wfile)
|
||||
f.close()
|
||||
else: # thumbnail couldn't be generated
|
||||
self.send_head(http.client.PARTIAL_CONTENT)
|
||||
return
|
||||
elif frame.status == ERROR:
|
||||
self.send_head(http.client.PARTIAL_CONTENT)
|
||||
else:
|
||||
# no such frame
|
||||
self.send_head(http.client.NO_CONTENT)
|
||||
else:
|
||||
# no such job id
|
||||
self.send_head(http.client.NO_CONTENT)
|
||||
else:
|
||||
# invalid url
|
||||
self.send_head(http.client.NO_CONTENT)
|
||||
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
elif self.path.startswith("/log"):
|
||||
match = log_pattern.match(self.path)
|
||||
|
||||
@@ -749,8 +766,6 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
|
||||
if not slave.id in job.blacklist:
|
||||
job.blacklist.append(slave.id)
|
||||
|
||||
self.server.stats("", "Receiving result")
|
||||
|
||||
slave.finishedFrame(job_frame)
|
||||
|
||||
frame.status = job_result
|
||||
@@ -766,6 +781,44 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
|
||||
else: # invalid slave id
|
||||
self.send_head(http.client.NO_CONTENT)
|
||||
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
elif self.path == "/thumb":
|
||||
self.server.stats("", "Receiving thumbnail result")
|
||||
|
||||
# need some message content here or the slave doesn't like it
|
||||
self.wfile.write(bytes("foo", encoding='utf8'))
|
||||
|
||||
slave_id = self.headers['slave-id']
|
||||
|
||||
slave = self.server.getSeenSlave(slave_id)
|
||||
|
||||
if slave: # only if slave id is valid
|
||||
job_id = self.headers['job-id']
|
||||
|
||||
job = self.server.getJobID(job_id)
|
||||
|
||||
if job:
|
||||
job_frame = int(self.headers['job-frame'])
|
||||
|
||||
frame = job[job_frame]
|
||||
|
||||
if frame:
|
||||
if job.type == netrender.model.JOB_BLENDER:
|
||||
length = int(self.headers['content-length'])
|
||||
buf = self.rfile.read(length)
|
||||
f = open(job.save_path + "%04d" % job_frame + ".jpg", 'wb')
|
||||
f.write(buf)
|
||||
f.close()
|
||||
|
||||
del buf
|
||||
|
||||
self.send_head()
|
||||
else: # frame not found
|
||||
self.send_head(http.client.NO_CONTENT)
|
||||
else: # job not found
|
||||
self.send_head(http.client.NO_CONTENT)
|
||||
else: # invalid slave id
|
||||
self.send_head(http.client.NO_CONTENT)
|
||||
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
elif self.path.startswith("/log"):
|
||||
self.server.stats("", "Receiving log file")
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ function showThumb(job, frame)
|
||||
function toggleThumb(job, frame)
|
||||
{
|
||||
img = document.images["thumb" + frame];
|
||||
url = "/render_" + job + "_" + frame + ".jpg"
|
||||
url = "/thumb_" + job + "_" + frame + ".jpg"
|
||||
|
||||
if (img.style.display == "block") {
|
||||
img.style.display = "none";
|
||||
|
||||
@@ -213,14 +213,26 @@ def render_slave(engine, netsettings, threads):
|
||||
headers["job-result"] = str(DONE)
|
||||
for frame in job.frames:
|
||||
headers["job-frame"] = str(frame.number)
|
||||
|
||||
if job.type == netrender.model.JOB_BLENDER:
|
||||
# send image back to server
|
||||
f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb')
|
||||
|
||||
filename = JOB_PREFIX + "%06d" % frame.number + ".exr"
|
||||
|
||||
# thumbnail first
|
||||
if netsettings.slave_thumb:
|
||||
thumbname = thumbnail(filename)
|
||||
|
||||
f = open(thumbname, 'rb')
|
||||
conn.request("PUT", "/thumb", f, headers=headers)
|
||||
f.close()
|
||||
conn.getresponse()
|
||||
|
||||
f = open(filename, 'rb')
|
||||
conn.request("PUT", "/render", f, headers=headers)
|
||||
f.close()
|
||||
if conn.getresponse().status == http.client.NO_CONTENT:
|
||||
continue
|
||||
|
||||
elif job.type == netrender.model.JOB_PROCESS:
|
||||
conn.request("PUT", "/render", headers=headers)
|
||||
if conn.getresponse().status == http.client.NO_CONTENT:
|
||||
|
||||
@@ -140,6 +140,7 @@ class RENDER_PT_network_slave_settings(RenderButtonsPanel):
|
||||
netsettings = scene.network_render
|
||||
|
||||
layout.prop(netsettings, "slave_clear")
|
||||
layout.prop(netsettings, "slave_thumb")
|
||||
layout.label(text="Threads:")
|
||||
layout.prop(rd, "threads_mode", expand=True)
|
||||
sub = layout.column()
|
||||
@@ -356,6 +357,11 @@ NetRenderSettings.BoolProperty( attr="slave_clear",
|
||||
description="delete downloaded files on exit",
|
||||
default = True)
|
||||
|
||||
NetRenderSettings.BoolProperty( attr="slave_thumb",
|
||||
name="Generate thumbnails",
|
||||
description="Generate thumbnails on slaves instead of master",
|
||||
default = False)
|
||||
|
||||
NetRenderSettings.BoolProperty( attr="master_clear",
|
||||
name="Clear on exit",
|
||||
description="delete saved files on exit",
|
||||
|
||||
@@ -28,7 +28,7 @@ try:
|
||||
except:
|
||||
bpy = None
|
||||
|
||||
VERSION = bytes("0.7", encoding='utf8')
|
||||
VERSION = bytes("0.8", encoding='utf8')
|
||||
|
||||
# Jobs status
|
||||
JOB_WAITING = 0 # before all data has been entered
|
||||
@@ -172,3 +172,28 @@ def prefixPath(prefix_directory, file_path, prefix_path):
|
||||
full_path = prefix_directory + file_path
|
||||
|
||||
return full_path
|
||||
|
||||
def thumbnail(filename):
|
||||
root = os.path.splitext(filename)[0]
|
||||
imagename = os.path.split(filename)[1]
|
||||
thumbname = root + ".jpg"
|
||||
|
||||
if os.path.exists(thumbname):
|
||||
return thumbname
|
||||
|
||||
if bpy:
|
||||
sce = bpy.data.scenes[0]
|
||||
sce.render_data.file_format = "JPEG"
|
||||
sce.render_data.quality = 90
|
||||
bpy.ops.image.open(path = filename)
|
||||
img = bpy.data.images[imagename]
|
||||
img.save(thumbname, scene = sce)
|
||||
|
||||
try:
|
||||
process = subprocess.Popen(["convert", thumbname, "-resize", "300x300", thumbname])
|
||||
process.wait()
|
||||
return thumbname
|
||||
except:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user