images can be placed on the working area, rotated and translated.

This commit is contained in:
Teja 2015-08-06 22:45:55 +02:00
parent 4879aafb72
commit 8adf72a4be
5 changed files with 141 additions and 12 deletions

View file

@ -24,8 +24,10 @@ def full_extension_tree():
result = dict(
# extensions for 3d model files
model=dict(
stl=["svg"]
stl=["svg"],
image=['jpg', 'jpeg', 'png', 'gif', 'bmp', 'pcx', 'webp']
),
# extensions for printable machine code
machinecode=dict(
gcode=["gcode", "gco", "g", "nc"]

View file

@ -111,7 +111,7 @@ $(function(){
url: API_BASEURL + "printer/printhead",
type: "POST",
dataType: "json",
contentType: "application/json; charset=UTF-8",
contentType: "application/json; charset=UTF8",
data: JSON.stringify({"command": "position", x:x, y:y})
});
}
@ -387,6 +387,49 @@ $(function(){
};
self.placeIMG = function (file) {
var url = self._getIMGserveUrl(file);
var img = new Image();
img.onload = function () {
var wpx = this.width;
var hpx = this.height;
var dimPT = self.getUsefulDimensions(wpx, hpx);
var wPT = dimPT[0];
var hPT = dimPT[1];
var y = self.mm2svgUnits(self.workingAreaHeightMM()) - hPT;
var newImg = snap.image(url, 0, y, wPT, hPT);
var id = self.getEntryId(file);
var previewId = self.generateUniqueId(id); // appends # if multiple times the same design is placed.
newImg.attr({id: previewId, filter: 'url(#grayscale_filter)'});
snap.select("#userContent").append(newImg);
newImg.transformable();
newImg.ftRegisterCallback(self.svgTransformUpdate);
file.id = previewId;
file.previewId = previewId;
file.url = url;
file.subtype = "bitmap";
self.placedDesigns.push(file);
};
img.src = url;
};
self.removeIMG = function(file){
self.removeSVG(file);
};
self.getUsefulDimensions = function(wpx, hpx){
var maxWidthMM = wpx * 0.25; // TODO parametrize
var aspectRatio = wpx / hpx;
var destWidthMM = Math.min(self.workingAreaWidthMM(), 100, maxWidthMM);
var destHeightMM = destWidthMM / aspectRatio;
var destWidthPT = self.mm2svgUnits(destWidthMM);
var destHeightPT = self.mm2svgUnits(destHeightMM);
return [destWidthPT, destHeightPT];
};
self.getDocumentDimensionsInPt = function(doc_width, doc_height, doc_viewbox){
if(doc_width === null){
// assume defaults if not set
@ -426,7 +469,7 @@ $(function(){
};
self.getDocumentViewBoxMatrix = function(widthStr, heightStr, vbox){
var dim = self.getDocumentDimensionsInPt(widthStr, heightStr, vbox)
var dim = self.getDocumentDimensionsInPt(widthStr, heightStr, vbox);
if(vbox !== null ){
var widthPx = dim[0];
var heightPx = dim[1];
@ -488,13 +531,23 @@ $(function(){
}
};
self._getIMGserveUrl = function(file){
return self._getSVGserveUrl(file);
};
self.templateFor = function(data) {
var extension = data.name.split('.').pop().toLowerCase();
if (extension === "svg") {
return "wa_template_" + data.type + "_svg";
if(data.type === "model" || data.type === "machinecode"){
var extension = data.name.split('.').pop().toLowerCase();
if (extension === "svg") {
return "wa_template_" + data.type + "_svg";
} else if (_.contains(['jpg', 'jpeg', 'png', 'gif', 'bmp', 'pcx', 'webp'], extension)) {
return "wa_template_" + data.type + "_img";
} else {
return "wa_template_" + data.type;
}
} else {
return "wa_template_" + data.type;
return "wa_template_dummy";
}
};

View file

@ -606,7 +606,7 @@ class Server():
(r"/downloads/files/local/(.*)", util.tornado.LargeResponseHandler, dict(path=s.getBaseFolder("uploads"), as_attachment=True, path_validation=util.tornado.path_validation_factory(lambda path: not os.path.basename(path).startswith("."), status_code=404))),
(r"/downloads/logs/([^/]*)", util.tornado.LargeResponseHandler, dict(path=s.getBaseFolder("logs"), as_attachment=True, access_validation=util.tornado.access_validation_factory(app, loginManager, util.flask.admin_validator))),
# serve instead of downloads for preview // as_attachment=False
(r"/serve/files/local/([^/]*\.(gco|gcode|g|nc|svg))", util.tornado.LargeResponseHandler, dict(path=s.getBaseFolder("uploads"), as_attachment=False)),
(r"/serve/files/local/([^/]*\.(gco|gcode|g|nc|svg|jpg|jpeg|png|gif|bmp|pcx|webp))", util.tornado.LargeResponseHandler, dict(path=s.getBaseFolder("uploads"), as_attachment=False)),
# camera snapshot
(r"/downloads/camera/current", util.tornado.UrlForwardHandler, dict(url=s.get(["webcam", "snapshot"]), as_attachment=True, access_validation=util.tornado.access_validation_factory(app, loginManager, util.flask.user_validator))),
# generated webassets

View file

@ -245,12 +245,26 @@ $(function() {
return data["prints"]["last"]["success"] ? "text-success" : "text-error";
};
// self.templateFor = function(data) {
// var extension = data.name.split('.').pop().toLowerCase();
// if (extension === "svg") {
// return "files_template_" + data.type + "_svg";
// } else {
// return "files_template_" + data.type;
// }
// };
self.templateFor = function(data) {
var extension = data.name.split('.').pop().toLowerCase();
if (extension === "svg") {
return "files_template_" + data.type + "_svg";
if(data.type === "model" || data.type === "machinecode"){
var extension = data.name.split('.').pop().toLowerCase();
if (extension === "svg") {
return "files_template_" + data.type + "_svg";
} else if (_.contains(['jpg', 'jpeg', 'png', 'gif', 'bmp', 'pcx', 'webp'], extension)) {
return "files_template_" + data.type + "_img";
} else {
return "files_template_" + data.type;
}
} else {
return "files_template_" + data.type;
return "files_template_dummy";
}
};

View file

@ -220,6 +220,31 @@
</div>
</div>
</script>
<script type="text/html" id="wa_template_model_img">
<div class="file_list_entry">
<div class="title muted pull-left" data-bind="text: name"></div>
<div class="btn-group action-buttons pull-right">
<div class="btn btn-mini" data-bind="click: function() { $root.toggleTransformHandles($data); }"><i class="icon-move" title="{{ _('Transform') }}"></i></div>
<div class="btn btn-mini" data-bind="click: function() { $root.removeIMG($data); }"><i class="icon-remove" title="{{ _('Remove') }}"></i></div>
</div>
<div class="detail_information" >
<div class="local_transformation muted">
<i class="icon-move" title="{{ _('translation') }}"></i>
<span class="translation" >0,0</span>
<i class="icon-resize-full" title="{{ _('scale') }}"></i>
<span class="scale" >100%</span>
<i class="icon-repeat" title="{{ _('rotation') }}"></i>
<span class="rotation" >0°</span>
</div>
<div class="misfit_warning" >
<i class="icon-exclamation-sign" style="color:red;" title="{{ _('exceeds working area') }}"> Design exceeds the working area.</i>
<a href="#" data-bind="click: function(){ $root.fitSVG($data) } ">Make it fit</a>
</div>
</div>
</div>
</script>
@ -241,6 +266,9 @@
height: workingAreaHeightPx()+'px'
}
">
<filter id = "grayscale_filter">
<feColorMatrix in = "SourceGraphic" type = "saturate" values = "0"/>
</filter>
<g id="scaleGroup" data-bind="attr: { transform: scaleMatrix() }">
<rect data-bind="click: move_laser"
id="coordGrid" x="0" y="0" width="0" height="0"
@ -524,6 +552,38 @@
</div>
</div>
</script>
<script type="text/html" id="files_template_model_img">
<div class="file_list_entry">
<i class="icon-camera file_list_icon"></i>
<div class="title muted dropdown" >
<a type="button" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span data-bind="text: name"></span>
<span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu">
<li>
<a class="" data-bind="attr: {href: $root.downloadLink($data), css: {disabled: !$root.downloadLink($data)}}"><i class="icon-download-alt" title="{{ _('Download') }}"></i> {{ _('Download') }}</a>
</li>
<li>
<a class="" data-bind="click: function() { if ($root.enableRemove($data)) { $root.removeFile($data); } else { return; } }, css: {disabled: !$root.enableRemove($data)}"><i class="icon-trash" title="{{ _('Remove') }}"></i> {{ _('Remove') }}</a>
</li>
</ul>
</div>
<div class="uploaded">{{ _('Uploaded') }}: <span data-bind="text: formatTimeAgo(date)"></span></div>
<div class="size">{{ _('Size') }}: <span data-bind="text: formatSize(size)"></span></div>
<div class="btn-group action-buttons">
<!-- <a class="btn btn-mini" data-bind="attr: {href: $root.downloadLink($data), css: {disabled: !$root.downloadLink($data)}}"><i class="icon-download-alt" title="{{ _('Download') }}"></i></a>
<div class="btn btn-mini" data-bind="click: function() { if ($root.enableRemove($data)) { $root.removeFile($data); } else { return; } }, css: {disabled: !$root.enableRemove($data)}"><i class="icon-trash" title="{{ _('Remove') }}"></i></div>-->
<div class="btn" data-bind="click: function() { if(!$root.workingArea.isPlaced($data)){ $root.workingArea.placeIMG($data); } }, css: {disabled: $root.workingArea.isPlaced($data)}"><i class="icon-ok" title="{{ _('Use') }}">Add</i></div>
</div>
</div>
</script>
<script type="text/html" id="files_template_model_dummy">
<div class="file_list_entry">
</div>
</script>
<script type="text/html" id="files_template_folder">
<div class="title" data-bind="text: name"></div>