diff --git a/build/lib/gradio/inputs.py b/build/lib/gradio/inputs.py index 37dd72e4ce..54dafbbafe 100644 --- a/build/lib/gradio/inputs.py +++ b/build/lib/gradio/inputs.py @@ -241,19 +241,21 @@ class Image(InputComponent): Input type: Union[numpy.array, PIL.Image, str] """ - def __init__(self, shape=None, image_mode='RGB', invert_colors=False, source="upload", type="numpy", label=None): + def __init__(self, shape=None, image_mode='RGB', invert_colors=False, source="upload", tool="editor", type="numpy", label=None): ''' Parameters: shape (Tuple[int, int]): shape to crop and resize image to; if None, matches input image size. image_mode (str): "RGB" if color, or "L" if black and white. invert_colors (bool): whether to invert the image as a preprocessing step. source (str): Source of image. "upload" creates a box where user can drop an image file, "webcam" allows user to take snapshot from their webcam, "canvas" defaults to a white image that can be edited and drawn upon with tools. + tool (str): Tools used for editing. "editor" allows a full screen editor, "select" provides a cropping and zoom tool. type (str): Type of value to be returned by component. "numpy" returns a numpy array with shape (width, height, 3), "pil" returns a PIL image object, "file" returns a temporary file object whose path can be retrieved by file_obj.name. label (str): component name in interface. ''' self.shape = shape self.image_mode = image_mode self.source = source + self.tool = tool self.type = type self.invert_colors = invert_colors super().__init__(label) @@ -270,6 +272,7 @@ class Image(InputComponent): return { "image_mode": self.image_mode, "source": self.source, + "tool": self.tool, **super().get_template_context() } diff --git a/build/lib/gradio/networking.py b/build/lib/gradio/networking.py index 82b5021a14..ce749b97bb 100644 --- a/build/lib/gradio/networking.py +++ b/build/lib/gradio/networking.py @@ -151,13 +151,11 @@ def serve_files_in_background(interface, port, directory_to_serve=None, server_n if self.path == "/api/predict/": # Make the prediction. self._set_headers() - print("in") data_string = self.rfile.read( int(self.headers["Content-Length"])) msg = json.loads(data_string) raw_input = msg["data"] prediction, durations = interface.process(raw_input) - print("prediction") output = {"data": prediction, "durations": durations} self.wfile.write(json.dumps(output).encode()) diff --git a/build/lib/gradio/static/css/vendor/cropper.min.css b/build/lib/gradio/static/css/vendor/cropper.min.css new file mode 100644 index 0000000000..6bdccb8add --- /dev/null +++ b/build/lib/gradio/static/css/vendor/cropper.min.css @@ -0,0 +1,9 @@ +/*! + * Cropper.js v1.5.7 + * https://fengyuanchen.github.io/cropperjs + * + * Copyright 2015-present Chen Fengyuan + * Released under the MIT license + * + * Date: 2020-05-23T05:22:57.283Z + */.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.cropper-container img{display:block;height:100%;image-orientation:0deg;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-canvas,.cropper-wrap-box{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:rgba(51,153,255,.75);overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:33.33333%;left:0;top:33.33333%;width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:33.33333%;top:0;width:33.33333%}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:after,.cropper-center:before{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media (min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media (min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media (min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed} \ No newline at end of file diff --git a/build/lib/gradio/static/js/all_io.js b/build/lib/gradio/static/js/all_io.js index 0bdb9c032a..d9958b5176 100644 --- a/build/lib/gradio/static/js/all_io.js +++ b/build/lib/gradio/static/js/all_io.js @@ -1,6 +1,7 @@ var io_master_template = { gather: function() { this.clear(); + this.gathering = true; for (let iface of this.input_interfaces) { iface.submit(); } @@ -8,12 +9,16 @@ var io_master_template = { clear: function() { this.last_input = new Array(this.input_interfaces.length); this.input_count = 0; + if (this.gather_timeout) { + window.clearTimeout(this.gather_timeout); + } }, input: function(interface_id, data) { this.last_input[interface_id] = data; this.input_count += 1; if (this.input_count == this.input_interfaces.length) { this.submit(); + this.gathering = false; } }, submit: function() { @@ -48,7 +53,7 @@ var io_master_template = { if (this.config.live) { var io = this; var refresh_lag = this.config.refresh_lag || 0; - window.setTimeout(function() { + this.gather_timeout = window.setTimeout(function() { io.gather(); }, refresh_lag); } else { @@ -56,6 +61,15 @@ var io_master_template = { this.target.find(".output_interfaces").css("opacity", 1); } }, + no_input: function() { + if (this.gathering && this.config.live) { + var io = this; + this.gather_timeout = window.setTimeout(function() { + io.gather(); + }, 200); + } + this.gathering = false; + }, flag: function() { var post_data = { 'data': { diff --git a/build/lib/gradio/static/js/interfaces/input/image.js b/build/lib/gradio/static/js/interfaces/input/image.js index 94030d1faf..9d8f029c2e 100644 --- a/build/lib/gradio/static/js/interfaces/input/image.js +++ b/build/lib/gradio/static/js/interfaces/input/image.js @@ -45,6 +45,7 @@ const image_input = { init: function(opts) { var io = this; this.source = opts.source; + this.tool = opts.tool; $('body').append(this.overlay_html.format(this.id)); this.overlay_target = $(`.overlay[interface_id=${this.id}]`); if (this.source == "upload") { @@ -139,9 +140,15 @@ const image_input = { var io = this; if (this.source == "canvas") { var dataURL = this.canvas.toDataURL("image/png"); - this.io_master.input(this.id, dataURL); + this.io_master.input(this.id, dataURL); } else if (this.state == "IMAGE_LOADED") { - io.io_master.input(io.id, this.image_data); + if (io.tool == "select") { + let canvas = io.cropper.getCroppedCanvas(); + var dataURL = canvas.toDataURL("image/png"); + this.io_master.input(this.id, dataURL); + } else { + io.io_master.input(io.id, this.image_data); + } } else if (this.source == "webcam") { Webcam.snap(function(image_data) { io.target.find(".webcam").hide(); @@ -150,6 +157,8 @@ const image_input = { io.state = "IMAGE_LOADED"; io.io_master.input(io.id, image_data); }); + } else { + io.io_master.no_input(); } }, clear: function() { @@ -164,6 +173,9 @@ const image_input = { this.target.find(".hidden_upload").prop("value", "") this.state = "NO_IMAGE"; this.image_data = null; + if (this.cropper) { + this.cropper.destroy(); + } } }, state: "NO_IMAGE", @@ -179,7 +191,10 @@ const image_input = { io.tui_editor.ui.resizeEditor({ imageSize: sizeValue }); }); } - }, + if (io.tool == "select") { + io.cropper = new Cropper(io.target.find(".image_preview")[0]); + } +}, load_preview_from_files: function(files) { if (!files.length || !window.FileReader || !/^image/.test(files[0].type)) { return diff --git a/build/lib/gradio/static/js/vendor/cropper.min.js b/build/lib/gradio/static/js/vendor/cropper.min.js new file mode 100644 index 0000000000..6896c806b7 --- /dev/null +++ b/build/lib/gradio/static/js/vendor/cropper.min.js @@ -0,0 +1,10 @@ +/*! + * Cropper.js v1.5.7 + * https://fengyuanchen.github.io/cropperjs + * + * Copyright 2015-present Chen Fengyuan + * Released under the MIT license + * + * Date: 2020-05-23T05:23:00.081Z + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Cropper=e()}(this,function(){"use strict";function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function n(t,e){for(var i=0;it.length)&&(e=t.length);for(var i=0,a=new Array(e);it.width?3===i?h=t.height*r:s=t.width/r:3===i?s=t.width/r:h=t.height*r;var c={aspectRatio:r,naturalWidth:n,naturalHeight:o,width:h,height:s};c.left=(t.width-h)/2,c.top=(t.height-s)/2,c.oldLeft=c.left,c.oldTop=c.top,this.canvasData=c,this.limited=1===i||2===i,this.limitCanvas(!0,!0),this.initialImageData=rt({},e),this.initialCanvasData=rt({},c)},limitCanvas:function(t,e){var i,a,n,o,r,h=this.options,s=this.containerData,c=this.canvasData,d=this.cropBoxData,l=h.viewMode,p=c.aspectRatio,m=this.cropped&&d;t&&(a=Number(h.minCanvasWidth)||0,n=Number(h.minCanvasHeight)||0,1=s.width&&(c.minLeft=Math.min(0,o),c.maxLeft=Math.max(0,o)),c.height>=s.height&&(c.minTop=Math.min(0,r),c.maxTop=Math.max(0,r))))):(c.minLeft=-c.width,c.minTop=-c.height,c.maxLeft=s.width,c.maxTop=s.height))},renderCanvas:function(t,e){var i,a,n,o,r,h=this.canvasData,s=this.imageData;e&&(a=(i=function(t){var e=t.width,i=t.height,a=t.degree;if(90===(a=Math.abs(a)%180))return{width:i,height:e};var n=a%90*Math.PI/180,o=Math.sin(n),r=Math.cos(n),h=e*r+i*o,s=e*o+i*r;return 90h.maxWidth||h.widthh.maxHeight||h.heighte.width?n.height=n.width/i:n.width=n.height*i),this.cropBoxData=n,this.limitCropBox(!0,!0),n.width=Math.min(Math.max(n.width,n.minWidth),n.maxWidth),n.height=Math.min(Math.max(n.height,n.minHeight),n.maxHeight),n.width=Math.max(n.minWidth,n.width*a),n.height=Math.max(n.minHeight,n.height*a),n.left=e.left+(e.width-n.width)/2,n.top=e.top+(e.height-n.height)/2,n.oldLeft=n.left,n.oldTop=n.top,this.initialCropBoxData=rt({},n)},limitCropBox:function(t,e){var i,a,n,o,r=this.options,h=this.containerData,s=this.canvasData,c=this.cropBoxData,d=this.limited,l=r.aspectRatio;t&&(n=Number(r.minCropBoxWidth)||0,o=Number(r.minCropBoxHeight)||0,i=d?Math.min(h.width,s.width,s.width+s.left,h.width-s.left):h.width,a=d?Math.min(h.height,s.height,s.height+s.top,h.height-s.top):h.height,n=Math.min(n,h.width),o=Math.min(o,h.height),l&&(n&&o?ni.maxWidth||i.widthi.maxHeight||i.height=e.width&&i.height>=e.height?E:O),ct(this.cropBox,rt({width:i.width,height:i.height},Lt({translateX:i.left,translateY:i.top}))),this.cropped&&this.limited&&this.limitCanvas(!0,!0),this.disabled||this.output()},output:function(){this.preview(),Ot(this.element,y,this.getData())}},jt={initPreview:function(){var t,e=this.element,i=this.crossOrigin,a=this.options.preview,n=i?this.crossOriginUrl:this.url,o=e.alt||"The image to preview",r=document.createElement("img");i&&(r.crossOrigin=i),r.src=n,r.alt=o,this.viewBox.appendChild(r),this.viewBoxImage=r,a&&("string"==typeof(t=a)?t=e.ownerDocument.querySelectorAll(a):a.querySelector&&(t=[a]),ot(this.previews=t,function(t){var e=document.createElement("img");ft(t,f,{width:t.offsetWidth,height:t.offsetHeight,html:t.innerHTML}),i&&(e.crossOrigin=i),e.src=n,e.alt=o,e.style.cssText='display:block;width:100%;height:auto;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;image-orientation:0deg!important;"',t.innerHTML="",t.appendChild(e)}))},resetPreview:function(){ot(this.previews,function(t){var e=gt(t,f);ct(t,{width:e.width,height:e.height}),t.innerHTML=e.html,function(e,i){if(_(e[i]))try{delete e[i]}catch(t){e[i]=void 0}else if(e.dataset)try{delete e.dataset[i]}catch(t){e.dataset[i]=void 0}else e.removeAttribute("data-".concat(ut(i)))}(t,f)})},preview:function(){var h=this.imageData,t=this.canvasData,e=this.cropBoxData,s=e.width,c=e.height,d=h.width,l=h.height,p=e.left-t.left-h.left,m=e.top-t.top-h.top;this.cropped&&!this.disabled&&(ct(this.viewBoxImage,rt({width:d,height:l},Lt(rt({translateX:-p,translateY:-m},h)))),ot(this.previews,function(t){var e=gt(t,f),i=e.width,a=e.height,n=i,o=a,r=1;s&&(o=c*(r=i/s)),c&&av&&(B.x=v-m);break;case H:c+B.xw&&(B.y=w-u)}}var x,M,C,D=r[Object.keys(r)[0]],B={x:D.endX-D.startX,y:D.endY-D.startY};switch(h){case O:c+=B.x,d+=B.y;break;case N:if(0<=B.x&&(v<=m||s&&(d<=f||w<=u))){b=!1;break}y(N),(l+=B.x)<0&&(h=H,c-=l=-l),s&&(p=l/s,d+=(o.height-p)/2);break;case z:if(B.y<=0&&(d<=f||s&&(c<=g||v<=m))){b=!1;break}y(z),p-=B.y,d+=B.y,p<0&&(h=L,d-=p=-p),s&&(l=p*s,c+=(o.width-l)/2);break;case H:if(B.x<=0&&(c<=g||s&&(d<=f||w<=u))){b=!1;break}y(H),l-=B.x,c+=B.x,l<0&&(h=N,c-=l=-l),s&&(p=l/s,d+=(o.height-p)/2);break;case L:if(0<=B.y&&(w<=u||s&&(c<=g||v<=m))){b=!1;break}y(L),(p+=B.y)<0&&(h=z,d-=p=-p),s&&(l=p*s,c+=(o.width-l)/2);break;case Y:if(s){if(B.y<=0&&(d<=f||v<=m)){b=!1;break}y(z),p-=B.y,d+=B.y,l=p*s}else y(z),y(N),!(0<=B.x)||m or element.");this.element=t,this.options=rt({},Z,et(e)&&e),this.cropped=!1,this.disabled=!1,this.pointers={},this.ready=!1,this.reloading=!1,this.replaced=!1,this.sized=!1,this.sizing=!1,this.init()}var t,e,a;return t=i,a=[{key:"noConflict",value:function(){return window.Cropper=$t,i}},{key:"setDefaults",value:function(t){rt(Z,et(t)&&t)}}],(e=[{key:"init",value:function(){var t,e=this.element,i=e.tagName.toLowerCase();if(!e[d]){if(e[d]=this,"img"===i){if(this.isImg=!0,t=e.getAttribute("src")||"",!(this.originalUrl=t))return;t=e.src}else"canvas"===i&&window.HTMLCanvasElement&&(t=e.toDataURL());this.load(t)}}},{key:"load",value:function(t){var e,i,a,n,o,r,h,s,c=this;t&&(this.url=t,this.imageData={},e=this.element,(i=this.options).rotatable||i.scalable||(i.checkOrientation=!1),i.checkOrientation&&window.ArrayBuffer?$.test(t)?Q.test(t)?this.read((a=t.replace(Rt,""),n=atob(a),o=new ArrayBuffer(n.length),ot(r=new Uint8Array(o),function(t,e){r[e]=n.charCodeAt(e)}),o)):this.clone():(h=new XMLHttpRequest,s=this.clone.bind(this),this.reloading=!0,(this.xhr=h).onabort=s,h.onerror=s,h.ontimeout=s,h.onprogress=function(){h.getResponseHeader("content-type")!==U&&h.abort()},h.onload=function(){c.read(h.response)},h.onloadend=function(){c.reloading=!1,c.xhr=null},i.checkCrossOrigin&&Nt(t)&&e.crossOrigin&&(t=Ht(t)),h.open("GET",t),h.responseType="arraybuffer",h.withCredentials="use-credentials"===e.crossOrigin,h.send()):this.clone())}},{key:"read",value:function(t){var e,i=this.options,a=this.imageData,n=St(t),o=0,r=1,h=1;1
',r=(o=n.querySelector(".".concat(d,"-container"))).querySelector(".".concat(d,"-canvas")),h=o.querySelector(".".concat(d,"-drag-box")),c=(s=o.querySelector(".".concat(d,"-crop-box"))).querySelector(".".concat(d,"-face")),this.container=a,this.cropper=o,this.canvas=r,this.dragBox=h,this.cropBox=s,this.viewBox=o.querySelector(".".concat(d,"-view-box")),this.face=c,r.appendChild(i),dt(t,A),a.insertBefore(o,t.nextSibling),this.isImg||lt(i,l),this.initPreview(),this.bind(),e.initialAspectRatio=Math.max(0,e.initialAspectRatio)||NaN,e.aspectRatio=Math.max(0,e.aspectRatio)||NaN,e.viewMode=Math.max(0,Math.min(3,Math.round(e.viewMode)))||0,dt(s,A),e.guides||dt(s.getElementsByClassName("".concat(d,"-dashed")),A),e.center||dt(s.getElementsByClassName("".concat(d,"-center")),A),e.background&&dt(o,"".concat(d,"-bg")),e.highlight||dt(c,p),e.cropBoxMovable&&(dt(c,u),ft(c,g,O)),e.cropBoxResizable||(dt(s.getElementsByClassName("".concat(d,"-line")),A),dt(s.getElementsByClassName("".concat(d,"-point")),A)),this.render(),this.ready=!0,this.setDragMode(e.dragMode),e.autoCrop&&this.crop(),this.setData(e.data),it(e.ready)&&kt(t,"ready",e.ready,{once:!0}),Ot(t,"ready"))}},{key:"unbuild",value:function(){this.ready&&(this.ready=!1,this.unbind(),this.resetPreview(),this.cropper.parentNode.removeChild(this.cropper),lt(this.element,A))}},{key:"uncreate",value:function(){this.ready?(this.unbuild(),this.ready=!1,this.cropped=!1):this.sizing?(this.sizingImage.onload=null,this.sizing=!1,this.sized=!1):this.reloading?(this.xhr.onabort=null,this.xhr.abort()):this.image&&this.stop()}}])&&n(t.prototype,e),a&&n(t,a),i}();return rt(Qt.prototype,At,jt,It,Pt,Ut,qt),Qt}); \ No newline at end of file diff --git a/build/lib/gradio/templates/index.html b/build/lib/gradio/templates/index.html index 3053940a3d..ab6bdeaa3c 100644 --- a/build/lib/gradio/templates/index.html +++ b/build/lib/gradio/templates/index.html @@ -37,6 +37,7 @@ + @@ -86,6 +87,7 @@ + diff --git a/demo/image_mod.py b/demo/image_mod.py index 91d3fc2b98..38bd047f53 100644 --- a/demo/image_mod.py +++ b/demo/image_mod.py @@ -8,7 +8,7 @@ def image_mod(image): gr.Interface(image_mod, - gr.inputs.Image(type="pil"), + gr.inputs.Image(type="pil", tool="select"), [ gr.outputs.Image(type="pil"), gr.outputs.Image(type="pil"), @@ -17,5 +17,6 @@ gr.Interface(image_mod, ["images/cheetah1.jpg"], ["images/cheetah2.jpg"], ["images/lion.jpg"], - ] + ], + live=True, ).launch(share=True) diff --git a/gradio.egg-info/SOURCES.txt b/gradio.egg-info/SOURCES.txt index fab06b74d4..652f245199 100644 --- a/gradio.egg-info/SOURCES.txt +++ b/gradio.egg-info/SOURCES.txt @@ -39,6 +39,7 @@ gradio/static/css/interfaces/output/json.css gradio/static/css/interfaces/output/key_values.css gradio/static/css/interfaces/output/label.css gradio/static/css/interfaces/output/textbox.css +gradio/static/css/vendor/cropper.min.css gradio/static/css/vendor/icons.svg gradio/static/css/vendor/jexcel.min.css gradio/static/css/vendor/jquery-ui.css @@ -95,6 +96,7 @@ gradio/static/js/interfaces/output/label.js gradio/static/js/interfaces/output/textbox.js gradio/static/js/vendor/FileSaver.min.js gradio/static/js/vendor/black-theme.js +gradio/static/js/vendor/cropper.min.js gradio/static/js/vendor/fabric.js gradio/static/js/vendor/html2canvas.min.js gradio/static/js/vendor/jexcel.min.js diff --git a/gradio/inputs.py b/gradio/inputs.py index 37dd72e4ce..54dafbbafe 100644 --- a/gradio/inputs.py +++ b/gradio/inputs.py @@ -241,19 +241,21 @@ class Image(InputComponent): Input type: Union[numpy.array, PIL.Image, str] """ - def __init__(self, shape=None, image_mode='RGB', invert_colors=False, source="upload", type="numpy", label=None): + def __init__(self, shape=None, image_mode='RGB', invert_colors=False, source="upload", tool="editor", type="numpy", label=None): ''' Parameters: shape (Tuple[int, int]): shape to crop and resize image to; if None, matches input image size. image_mode (str): "RGB" if color, or "L" if black and white. invert_colors (bool): whether to invert the image as a preprocessing step. source (str): Source of image. "upload" creates a box where user can drop an image file, "webcam" allows user to take snapshot from their webcam, "canvas" defaults to a white image that can be edited and drawn upon with tools. + tool (str): Tools used for editing. "editor" allows a full screen editor, "select" provides a cropping and zoom tool. type (str): Type of value to be returned by component. "numpy" returns a numpy array with shape (width, height, 3), "pil" returns a PIL image object, "file" returns a temporary file object whose path can be retrieved by file_obj.name. label (str): component name in interface. ''' self.shape = shape self.image_mode = image_mode self.source = source + self.tool = tool self.type = type self.invert_colors = invert_colors super().__init__(label) @@ -270,6 +272,7 @@ class Image(InputComponent): return { "image_mode": self.image_mode, "source": self.source, + "tool": self.tool, **super().get_template_context() } diff --git a/gradio/networking.py b/gradio/networking.py index 82b5021a14..ce749b97bb 100644 --- a/gradio/networking.py +++ b/gradio/networking.py @@ -151,13 +151,11 @@ def serve_files_in_background(interface, port, directory_to_serve=None, server_n if self.path == "/api/predict/": # Make the prediction. self._set_headers() - print("in") data_string = self.rfile.read( int(self.headers["Content-Length"])) msg = json.loads(data_string) raw_input = msg["data"] prediction, durations = interface.process(raw_input) - print("prediction") output = {"data": prediction, "durations": durations} self.wfile.write(json.dumps(output).encode()) diff --git a/gradio/static/css/vendor/cropper.min.css b/gradio/static/css/vendor/cropper.min.css new file mode 100644 index 0000000000..6bdccb8add --- /dev/null +++ b/gradio/static/css/vendor/cropper.min.css @@ -0,0 +1,9 @@ +/*! + * Cropper.js v1.5.7 + * https://fengyuanchen.github.io/cropperjs + * + * Copyright 2015-present Chen Fengyuan + * Released under the MIT license + * + * Date: 2020-05-23T05:22:57.283Z + */.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.cropper-container img{display:block;height:100%;image-orientation:0deg;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-canvas,.cropper-wrap-box{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:rgba(51,153,255,.75);overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:33.33333%;left:0;top:33.33333%;width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:33.33333%;top:0;width:33.33333%}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:after,.cropper-center:before{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media (min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media (min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media (min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed} \ No newline at end of file diff --git a/gradio/static/js/all_io.js b/gradio/static/js/all_io.js index 0bdb9c032a..d9958b5176 100644 --- a/gradio/static/js/all_io.js +++ b/gradio/static/js/all_io.js @@ -1,6 +1,7 @@ var io_master_template = { gather: function() { this.clear(); + this.gathering = true; for (let iface of this.input_interfaces) { iface.submit(); } @@ -8,12 +9,16 @@ var io_master_template = { clear: function() { this.last_input = new Array(this.input_interfaces.length); this.input_count = 0; + if (this.gather_timeout) { + window.clearTimeout(this.gather_timeout); + } }, input: function(interface_id, data) { this.last_input[interface_id] = data; this.input_count += 1; if (this.input_count == this.input_interfaces.length) { this.submit(); + this.gathering = false; } }, submit: function() { @@ -48,7 +53,7 @@ var io_master_template = { if (this.config.live) { var io = this; var refresh_lag = this.config.refresh_lag || 0; - window.setTimeout(function() { + this.gather_timeout = window.setTimeout(function() { io.gather(); }, refresh_lag); } else { @@ -56,6 +61,15 @@ var io_master_template = { this.target.find(".output_interfaces").css("opacity", 1); } }, + no_input: function() { + if (this.gathering && this.config.live) { + var io = this; + this.gather_timeout = window.setTimeout(function() { + io.gather(); + }, 200); + } + this.gathering = false; + }, flag: function() { var post_data = { 'data': { diff --git a/gradio/static/js/interfaces/input/image.js b/gradio/static/js/interfaces/input/image.js index 94030d1faf..9d8f029c2e 100644 --- a/gradio/static/js/interfaces/input/image.js +++ b/gradio/static/js/interfaces/input/image.js @@ -45,6 +45,7 @@ const image_input = { init: function(opts) { var io = this; this.source = opts.source; + this.tool = opts.tool; $('body').append(this.overlay_html.format(this.id)); this.overlay_target = $(`.overlay[interface_id=${this.id}]`); if (this.source == "upload") { @@ -139,9 +140,15 @@ const image_input = { var io = this; if (this.source == "canvas") { var dataURL = this.canvas.toDataURL("image/png"); - this.io_master.input(this.id, dataURL); + this.io_master.input(this.id, dataURL); } else if (this.state == "IMAGE_LOADED") { - io.io_master.input(io.id, this.image_data); + if (io.tool == "select") { + let canvas = io.cropper.getCroppedCanvas(); + var dataURL = canvas.toDataURL("image/png"); + this.io_master.input(this.id, dataURL); + } else { + io.io_master.input(io.id, this.image_data); + } } else if (this.source == "webcam") { Webcam.snap(function(image_data) { io.target.find(".webcam").hide(); @@ -150,6 +157,8 @@ const image_input = { io.state = "IMAGE_LOADED"; io.io_master.input(io.id, image_data); }); + } else { + io.io_master.no_input(); } }, clear: function() { @@ -164,6 +173,9 @@ const image_input = { this.target.find(".hidden_upload").prop("value", "") this.state = "NO_IMAGE"; this.image_data = null; + if (this.cropper) { + this.cropper.destroy(); + } } }, state: "NO_IMAGE", @@ -179,7 +191,10 @@ const image_input = { io.tui_editor.ui.resizeEditor({ imageSize: sizeValue }); }); } - }, + if (io.tool == "select") { + io.cropper = new Cropper(io.target.find(".image_preview")[0]); + } +}, load_preview_from_files: function(files) { if (!files.length || !window.FileReader || !/^image/.test(files[0].type)) { return diff --git a/gradio/static/js/vendor/cropper.min.js b/gradio/static/js/vendor/cropper.min.js new file mode 100644 index 0000000000..6896c806b7 --- /dev/null +++ b/gradio/static/js/vendor/cropper.min.js @@ -0,0 +1,10 @@ +/*! + * Cropper.js v1.5.7 + * https://fengyuanchen.github.io/cropperjs + * + * Copyright 2015-present Chen Fengyuan + * Released under the MIT license + * + * Date: 2020-05-23T05:23:00.081Z + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Cropper=e()}(this,function(){"use strict";function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function n(t,e){for(var i=0;it.length)&&(e=t.length);for(var i=0,a=new Array(e);it.width?3===i?h=t.height*r:s=t.width/r:3===i?s=t.width/r:h=t.height*r;var c={aspectRatio:r,naturalWidth:n,naturalHeight:o,width:h,height:s};c.left=(t.width-h)/2,c.top=(t.height-s)/2,c.oldLeft=c.left,c.oldTop=c.top,this.canvasData=c,this.limited=1===i||2===i,this.limitCanvas(!0,!0),this.initialImageData=rt({},e),this.initialCanvasData=rt({},c)},limitCanvas:function(t,e){var i,a,n,o,r,h=this.options,s=this.containerData,c=this.canvasData,d=this.cropBoxData,l=h.viewMode,p=c.aspectRatio,m=this.cropped&&d;t&&(a=Number(h.minCanvasWidth)||0,n=Number(h.minCanvasHeight)||0,1=s.width&&(c.minLeft=Math.min(0,o),c.maxLeft=Math.max(0,o)),c.height>=s.height&&(c.minTop=Math.min(0,r),c.maxTop=Math.max(0,r))))):(c.minLeft=-c.width,c.minTop=-c.height,c.maxLeft=s.width,c.maxTop=s.height))},renderCanvas:function(t,e){var i,a,n,o,r,h=this.canvasData,s=this.imageData;e&&(a=(i=function(t){var e=t.width,i=t.height,a=t.degree;if(90===(a=Math.abs(a)%180))return{width:i,height:e};var n=a%90*Math.PI/180,o=Math.sin(n),r=Math.cos(n),h=e*r+i*o,s=e*o+i*r;return 90h.maxWidth||h.widthh.maxHeight||h.heighte.width?n.height=n.width/i:n.width=n.height*i),this.cropBoxData=n,this.limitCropBox(!0,!0),n.width=Math.min(Math.max(n.width,n.minWidth),n.maxWidth),n.height=Math.min(Math.max(n.height,n.minHeight),n.maxHeight),n.width=Math.max(n.minWidth,n.width*a),n.height=Math.max(n.minHeight,n.height*a),n.left=e.left+(e.width-n.width)/2,n.top=e.top+(e.height-n.height)/2,n.oldLeft=n.left,n.oldTop=n.top,this.initialCropBoxData=rt({},n)},limitCropBox:function(t,e){var i,a,n,o,r=this.options,h=this.containerData,s=this.canvasData,c=this.cropBoxData,d=this.limited,l=r.aspectRatio;t&&(n=Number(r.minCropBoxWidth)||0,o=Number(r.minCropBoxHeight)||0,i=d?Math.min(h.width,s.width,s.width+s.left,h.width-s.left):h.width,a=d?Math.min(h.height,s.height,s.height+s.top,h.height-s.top):h.height,n=Math.min(n,h.width),o=Math.min(o,h.height),l&&(n&&o?ni.maxWidth||i.widthi.maxHeight||i.height=e.width&&i.height>=e.height?E:O),ct(this.cropBox,rt({width:i.width,height:i.height},Lt({translateX:i.left,translateY:i.top}))),this.cropped&&this.limited&&this.limitCanvas(!0,!0),this.disabled||this.output()},output:function(){this.preview(),Ot(this.element,y,this.getData())}},jt={initPreview:function(){var t,e=this.element,i=this.crossOrigin,a=this.options.preview,n=i?this.crossOriginUrl:this.url,o=e.alt||"The image to preview",r=document.createElement("img");i&&(r.crossOrigin=i),r.src=n,r.alt=o,this.viewBox.appendChild(r),this.viewBoxImage=r,a&&("string"==typeof(t=a)?t=e.ownerDocument.querySelectorAll(a):a.querySelector&&(t=[a]),ot(this.previews=t,function(t){var e=document.createElement("img");ft(t,f,{width:t.offsetWidth,height:t.offsetHeight,html:t.innerHTML}),i&&(e.crossOrigin=i),e.src=n,e.alt=o,e.style.cssText='display:block;width:100%;height:auto;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;image-orientation:0deg!important;"',t.innerHTML="",t.appendChild(e)}))},resetPreview:function(){ot(this.previews,function(t){var e=gt(t,f);ct(t,{width:e.width,height:e.height}),t.innerHTML=e.html,function(e,i){if(_(e[i]))try{delete e[i]}catch(t){e[i]=void 0}else if(e.dataset)try{delete e.dataset[i]}catch(t){e.dataset[i]=void 0}else e.removeAttribute("data-".concat(ut(i)))}(t,f)})},preview:function(){var h=this.imageData,t=this.canvasData,e=this.cropBoxData,s=e.width,c=e.height,d=h.width,l=h.height,p=e.left-t.left-h.left,m=e.top-t.top-h.top;this.cropped&&!this.disabled&&(ct(this.viewBoxImage,rt({width:d,height:l},Lt(rt({translateX:-p,translateY:-m},h)))),ot(this.previews,function(t){var e=gt(t,f),i=e.width,a=e.height,n=i,o=a,r=1;s&&(o=c*(r=i/s)),c&&av&&(B.x=v-m);break;case H:c+B.xw&&(B.y=w-u)}}var x,M,C,D=r[Object.keys(r)[0]],B={x:D.endX-D.startX,y:D.endY-D.startY};switch(h){case O:c+=B.x,d+=B.y;break;case N:if(0<=B.x&&(v<=m||s&&(d<=f||w<=u))){b=!1;break}y(N),(l+=B.x)<0&&(h=H,c-=l=-l),s&&(p=l/s,d+=(o.height-p)/2);break;case z:if(B.y<=0&&(d<=f||s&&(c<=g||v<=m))){b=!1;break}y(z),p-=B.y,d+=B.y,p<0&&(h=L,d-=p=-p),s&&(l=p*s,c+=(o.width-l)/2);break;case H:if(B.x<=0&&(c<=g||s&&(d<=f||w<=u))){b=!1;break}y(H),l-=B.x,c+=B.x,l<0&&(h=N,c-=l=-l),s&&(p=l/s,d+=(o.height-p)/2);break;case L:if(0<=B.y&&(w<=u||s&&(c<=g||v<=m))){b=!1;break}y(L),(p+=B.y)<0&&(h=z,d-=p=-p),s&&(l=p*s,c+=(o.width-l)/2);break;case Y:if(s){if(B.y<=0&&(d<=f||v<=m)){b=!1;break}y(z),p-=B.y,d+=B.y,l=p*s}else y(z),y(N),!(0<=B.x)||m or element.");this.element=t,this.options=rt({},Z,et(e)&&e),this.cropped=!1,this.disabled=!1,this.pointers={},this.ready=!1,this.reloading=!1,this.replaced=!1,this.sized=!1,this.sizing=!1,this.init()}var t,e,a;return t=i,a=[{key:"noConflict",value:function(){return window.Cropper=$t,i}},{key:"setDefaults",value:function(t){rt(Z,et(t)&&t)}}],(e=[{key:"init",value:function(){var t,e=this.element,i=e.tagName.toLowerCase();if(!e[d]){if(e[d]=this,"img"===i){if(this.isImg=!0,t=e.getAttribute("src")||"",!(this.originalUrl=t))return;t=e.src}else"canvas"===i&&window.HTMLCanvasElement&&(t=e.toDataURL());this.load(t)}}},{key:"load",value:function(t){var e,i,a,n,o,r,h,s,c=this;t&&(this.url=t,this.imageData={},e=this.element,(i=this.options).rotatable||i.scalable||(i.checkOrientation=!1),i.checkOrientation&&window.ArrayBuffer?$.test(t)?Q.test(t)?this.read((a=t.replace(Rt,""),n=atob(a),o=new ArrayBuffer(n.length),ot(r=new Uint8Array(o),function(t,e){r[e]=n.charCodeAt(e)}),o)):this.clone():(h=new XMLHttpRequest,s=this.clone.bind(this),this.reloading=!0,(this.xhr=h).onabort=s,h.onerror=s,h.ontimeout=s,h.onprogress=function(){h.getResponseHeader("content-type")!==U&&h.abort()},h.onload=function(){c.read(h.response)},h.onloadend=function(){c.reloading=!1,c.xhr=null},i.checkCrossOrigin&&Nt(t)&&e.crossOrigin&&(t=Ht(t)),h.open("GET",t),h.responseType="arraybuffer",h.withCredentials="use-credentials"===e.crossOrigin,h.send()):this.clone())}},{key:"read",value:function(t){var e,i=this.options,a=this.imageData,n=St(t),o=0,r=1,h=1;1
',r=(o=n.querySelector(".".concat(d,"-container"))).querySelector(".".concat(d,"-canvas")),h=o.querySelector(".".concat(d,"-drag-box")),c=(s=o.querySelector(".".concat(d,"-crop-box"))).querySelector(".".concat(d,"-face")),this.container=a,this.cropper=o,this.canvas=r,this.dragBox=h,this.cropBox=s,this.viewBox=o.querySelector(".".concat(d,"-view-box")),this.face=c,r.appendChild(i),dt(t,A),a.insertBefore(o,t.nextSibling),this.isImg||lt(i,l),this.initPreview(),this.bind(),e.initialAspectRatio=Math.max(0,e.initialAspectRatio)||NaN,e.aspectRatio=Math.max(0,e.aspectRatio)||NaN,e.viewMode=Math.max(0,Math.min(3,Math.round(e.viewMode)))||0,dt(s,A),e.guides||dt(s.getElementsByClassName("".concat(d,"-dashed")),A),e.center||dt(s.getElementsByClassName("".concat(d,"-center")),A),e.background&&dt(o,"".concat(d,"-bg")),e.highlight||dt(c,p),e.cropBoxMovable&&(dt(c,u),ft(c,g,O)),e.cropBoxResizable||(dt(s.getElementsByClassName("".concat(d,"-line")),A),dt(s.getElementsByClassName("".concat(d,"-point")),A)),this.render(),this.ready=!0,this.setDragMode(e.dragMode),e.autoCrop&&this.crop(),this.setData(e.data),it(e.ready)&&kt(t,"ready",e.ready,{once:!0}),Ot(t,"ready"))}},{key:"unbuild",value:function(){this.ready&&(this.ready=!1,this.unbind(),this.resetPreview(),this.cropper.parentNode.removeChild(this.cropper),lt(this.element,A))}},{key:"uncreate",value:function(){this.ready?(this.unbuild(),this.ready=!1,this.cropped=!1):this.sizing?(this.sizingImage.onload=null,this.sizing=!1,this.sized=!1):this.reloading?(this.xhr.onabort=null,this.xhr.abort()):this.image&&this.stop()}}])&&n(t.prototype,e),a&&n(t,a),i}();return rt(Qt.prototype,At,jt,It,Pt,Ut,qt),Qt}); \ No newline at end of file diff --git a/gradio/templates/index.html b/gradio/templates/index.html index 3053940a3d..ab6bdeaa3c 100644 --- a/gradio/templates/index.html +++ b/gradio/templates/index.html @@ -37,6 +37,7 @@ + @@ -86,6 +87,7 @@ +