1

Imageinspector

Objective
  • Responder
    • View
      • Inspector
        • ImageInspector

Click in the image. Select a JPG, PNG, GIF or SVG file. NOTE: The maximum size of the file is configured to 1Mb and the maximum width of the display to 320px. Move the pointer of the mouse over the image to display its dimensions. Open a folder containing images with the explorer of your file system. Drag and drop a JPG, PNG, GIF or SVG file over the image.

Try saving on your disk and loading the logo of Chrome, of Firefox or the acronym in SVG. NOTE: The dimensions of an SVG depend on the maximum width of the display (320px).

To start loading an image from a file with a button, a code can run the method loadImage of the inspector when the button is clicked. IMPORTANT: For security reasons, loadImage must be called in response to a user interaction.

<p><button id="btn_upload_image" type="submit" class="narrow" title=""><i class="fa fa-upload"></i></button></p>

And in JavaScript:

document.getElementById('btn_upload_image').onclick = (e) => inspector.loadImage();
  1. function ImageInspector(value = null, options = false) {
  2.     options = options || {};
  3.  
  4.     let filetypes = options.filetypes;
  5.     let maxsize = options.maxsize;
  6.  
  7.     let draganddrop = options.draganddrop === undefined ? true : (options.draganddrop ? true : false);
  8.     let loadonclick = options.loadonclick === undefined ? true : (options.loadonclick ? true : false);
  9.  
  10.     if (!this.validate(value))
  11.         throw new TypeError();
  12.  
  13.     if (filetypes === undefined)
  14.         filetypes = ImageInspector.defaultFileTypes;
  15.     else if (! (Array.isArray(filetypes) && filetypes.length > 0 && filetypes.every((e) => typeof e === 'string')))
  16.         throw new TypeError();
  17.  
  18.     if (maxsize === undefined)
  19.         maxsize = 0;
  20.     else if (typeof maxsize !== 'number')
  21.         throw new TypeError();
  22.     else if (maxsize < 0)
  23.         throw new RangeError();
  24.  
  25.     Inspector.call(this);
  26.  
  27.     if (value !== null) {
  28.         const [data, width, height] = value;
  29.  
  30.         this._value = data;
  31.         this._width = width;
  32.         this._height = height;
  33.     }
  34.  
  35.     this._type = undefined;
  36.     this._size = 0;
  37.  
  38.     this._filetypes = filetypes;
  39.     this._maxsize = maxsize;
  40.  
  41.     this._draganddrop = draganddrop;
  42.     this._loadonclick = loadonclick;
  43.  
  44.     this._imageWidget = null;
  45.     this._imageWidgetSrc = null;
  46. }
  47.  
  48. ImageInspector.prototype = Object.create(Inspector.prototype);
  49.  
  50. Object.defineProperty(ImageInspector.prototype, 'constructor', { value: ImageInspector, enumerable: false, writable: true });
  51.  
  52. ImageInspector.defaultFileTypes = ['image/jpeg', 'image/png', 'image/gif'];
  53.  
  54. Object.defineProperty(ImageInspector.prototype, 'width', {
  55.     get:    function() {
  56.                 return this._width;
  57.             }
  58. });
  59.  
  60. Object.defineProperty(ImageInspector.prototype, 'height', {
  61.     get:    function() {
  62.                 return this._height;
  63.             }
  64. });
  65.  
  66. Object.defineProperty(ImageInspector.prototype, 'type', {
  67.     get:    function() {
  68.                 if (!this._value)
  69.                     return undefined;
  70.  
  71.                 if (this._type === undefined)
  72.                     this._type = /^data:(image\/[-.+0-9a-zA-Z]+);base64,/.exec(this._value)[1];
  73.  
  74.                 return this._type;
  75.             }
  76. });
  77.  
  78. Object.defineProperty(ImageInspector.prototype, 'size', {
  79.     get:    function() {
  80.                 if (!this._value)
  81.                     return 0;
  82.  
  83.                 if (!this._size)
  84.                     this._size = atob(this._value.substring(this._value.indexOf(',')+1)).length;
  85.  
  86.                 return this._size;
  87.             }
  88. });
  89.  
  90. ImageInspector.prototype.validate = function(val) {
  91.     return val === null || (Array.isArray(val) && Validator.validateImageDataURL(val[0]) && Number.isInteger(val[1]) && Number.isInteger(val[2]) && val[1] >= 0 && val[2] >= 0);
  92. }
  93.  
  94. ImageInspector.prototype.get = function() {
  95.     return this._value ? [this._value, this._width, this._height] : null;
  96. }
  97.  
  98. ImageInspector.prototype.set = function(val) {
  99.     if (!this.validate(val))
  100.         return false;
  101.  
  102.     const [data, width, height] = val === null ? [null, 0, 0] : val;
  103.  
  104.     if (this._value !== data) {
  105.         this._value = data;
  106.  
  107.         this._width = width;
  108.         this._height = height;
  109.         this._type = undefined;
  110.         this._size = 0;
  111.  
  112.         if (this.interfaced())
  113.             this.resetWidget();
  114.     }
  115.  
  116.     return true;
  117. }
  118.  
  119. ImageInspector.prototype.loadImage = function() {
  120.     if (this._widget)
  121.         this._widget.click();
  122.  
  123.     return this;
  124. }
  125.  
  126. ImageInspector.prototype.reset = function() {
  127.     if (!this._widget)
  128.         return false;
  129.  
  130.     if (!this._imageWidget.src)
  131.         return false;
  132.  
  133.     this._loadurl(this._imageWidget.src);
  134.  
  135.     return true;
  136. }
  137.  
  138. ImageInspector.prototype.disable = function() {
  139.     Inspector.prototype.disable.call(this);
  140.  
  141.     if (this._imageWidget && this._loadonclick)
  142.         this._imageWidget.style.cursor = 'default';
  143.  
  144.     return this;
  145. }
  146.  
  147. ImageInspector.prototype.enable = function() {
  148.     Inspector.prototype.enable.call(this);
  149.  
  150.     if (this._imageWidget && this._loadonclick)
  151.         this._imageWidget.style.cursor = 'pointer';
  152.  
  153.     return this;
  154. }
  155.  
  156. ImageInspector.prototype.changeCallback = function(e) {
  157.     let val = e.target.value ? e.target.files[0] : false;
  158.  
  159.     if (val)
  160.         this._loadblob(e.target.files[0]);
  161. }
  162.  
  163. ImageInspector.prototype.resetWidget = function() {
  164.     if (this._imageWidget) {
  165.         this._imageWidget.src = this._value || this._imageWidgetSrc;
  166.  
  167.         this._imageWidget.setAttribute('title', this._value ? `${this._width}x${this._height}` : '');
  168.     }
  169.  
  170.     return this;
  171. }
  172.  
  173. ImageInspector.prototype.setWidget = function(w) {
  174.     if (w.tagName != 'IMG')
  175.         throw new TypeError();
  176.  
  177.     let input = document.createElement('input');
  178.  
  179.     input.type = 'file';
  180.     input.accept = this._filetypes.join(',');
  181.  
  182.     input.style.display = 'none';
  183.  
  184.     Inspector.prototype.setWidget.call(this, input);
  185.  
  186.     if (this._loadonclick) {
  187.         w.addEventListener('click', () => this.loadImage());
  188.         w.style.cursor = this.isEnabled() ? 'pointer' : 'default';
  189.     }
  190.  
  191.     if (this._draganddrop) {
  192.         w.addEventListener('drop', (e) => {
  193.             const dt = e.dataTransfer;
  194.  
  195.             e.preventDefault();
  196.  
  197.             if (dt.types.indexOf('Files') != -1) {
  198.                 this._loadblob(dt.files[0]);
  199.             }
  200.         });
  201.  
  202.         w.addEventListener('dragenter', (e) => {
  203.             const dt = e.dataTransfer;
  204.  
  205.             if (dt.types.indexOf('Files') != -1) {
  206.                 e.preventDefault();
  207.             }
  208.         });
  209.  
  210.         w.addEventListener('dragleave', (e) => {
  211.             e.preventDefault();
  212.         });
  213.  
  214.         w.addEventListener('dragover', (e) => {
  215.             const dt = e.dataTransfer;
  216.  
  217.             e.preventDefault();
  218.  
  219.             dt.dropEffect = dt.types.indexOf('Files') != -1 ? 'copy' : 'none';
  220.         });
  221.     }
  222.  
  223.     w.removeAttribute('width');
  224.     w.removeAttribute('height');
  225.  
  226.     w.after(input);
  227.  
  228.     this._imageWidget = w;
  229.     this._imageWidgetSrc = w.src;
  230.  
  231.     return this;
  232. }
  233.  
  234. ImageInspector.prototype.manageWidget = function(parent = null) {
  235.     Inspector.prototype.manageWidget.call(this, parent);
  236.  
  237.     if (this._parent && this._imageWidget)
  238.         this._parent.appendChild(this._imageWidget);
  239.  
  240.     return this;
  241. }
  242.  
  243. ImageInspector.prototype.unmanageWidget = function() {
  244.     Inspector.prototype.unmanageWidget.call(this);
  245.  
  246.     if (this._parent && this._imageWidget)
  247.         this._parent.removeChild(this._imageWidget);
  248.  
  249.     return this;
  250. }
  251.  
  252. ImageInspector.prototype.createWidget = function() {
  253.     const html = `<img src="${this._imageWidgetSrc}" alt="" title="" />`;
  254.  
  255.     let template = document.createElement('template');
  256.  
  257.     template.innerHTML = html;
  258.  
  259.     let widget = template.content.children[0];
  260.  
  261.     this.setWidget(widget);
  262.  
  263.     return this;
  264. }
  265.  
  266. ImageInspector.prototype.destroyWidget = function() {
  267.     Inspector.prototype.destroyWidget.call(this);
  268.  
  269.     this._imageWwidget = null;
  270.  
  271.     return this;
  272. }
  273.  
  274. ImageInspector.prototype._loadurl = function(url) {
  275.     const req = new XMLHttpRequest();
  276.  
  277.     req.open('GET', url);
  278.     req.responseType = 'blob';
  279.     req.setRequestHeader = this._filetypes.join(',');
  280.  
  281.     req.onload = () => this._loadblob(req.response, false);
  282.  
  283.     req.send();
  284. }
  285.  
  286. ImageInspector.prototype._loadblob = function(blob, notify = true) {
  287.     if (this._maxsize > 0 && blob.size > this._maxsize)
  288.         return;
  289.  
  290.     if (this._filetypes.indexOf(blob.type) == -1)
  291.         return;
  292.  
  293.     const reader = new FileReader();
  294.  
  295.     reader.onload = (e) => {
  296.         let data = e.target.result;
  297.  
  298.         if (this._value !== data) {
  299.             this._value = data;
  300.             this._width = this._height = 0
  301.             this._type = undefined;
  302.             this._size = blob.size;
  303.  
  304.             if (this._imageWidget) {
  305.                 this._imageWidget.addEventListener('load', (e) => this._onloadsrc(e), { once: true });
  306.                 this._imageWidget.src = data;
  307.             }
  308.         }
  309.     };
  310.  
  311.     reader.readAsDataURL(blob);
  312. }
  313.  
  314. ImageInspector.prototype._onloadsrc = function(e) {
  315.     const data = e.target.src;
  316.     const r = /^data:(image\/[-.+0-9a-zA-Z]+);base64,/.exec(data);
  317.  
  318.     if (r) {
  319.         const type = r[1];
  320.         const svg = type == 'image/svg+xml';
  321.  
  322.         const w = svg ? e.target.width : e.target.naturalWidth;
  323.         const h = svg ? e.target.height : e.target.naturalHeight;
  324.  
  325.         this._width = w;
  326.         this._height = h;
  327.         this._type = type;
  328.  
  329.         this._imageWidget.setAttribute('title', `${w}x${h}`);
  330.  
  331.         this.respondTo('inspectorValueChanged', this);
  332.     }
  333.     else
  334.         this._imageWidget.setAttribute('title', '');
  335. }
Test
  1. <?php $filetypes=array('image/jpeg', 'image/png', 'image/gif', 'image/svg+xml'); ?>
  2. <?php $maxsize=1000000; ?>
  3. <?php $width=320; ?>
  1. <?php $id=uniqid('id'); ?>
  1. .test_display img {
  2.     max-width: <?php echo $width; ?>px;
  3. }
  1. <div id="<?php echo $id; ?>" class="noprint">
  2. <div class="test_display"><img src="/files/images/htmlcssjs.jpg" alt=""/></div>
  3. </div>
  1. <?php head('javascript', '/objectivejs/Objective.js') ?>
  2. <?php head('javascript', '/objectivejs/Responder.js') ?>
  3. <?php head('javascript', '/objectivejs/View.js') ?>
  4. <?php head('javascript', '/objectivejs/Inspector.js') ?>
  5. <?php head('javascript', '/objectivejs/ImageInspector.js') ?>
  6. <?php head('javascript', '/objectivejs/Validator.js') ?>
  1. const filetypes = [<?php echo implode(',', array_map(function($s) { return "'$s'"; }, $filetypes)); ?>];
  2.  
  3. const inspector = new ImageInspector(null, { filetypes: filetypes, maxsize: <?php echo $maxsize; ?> });
  4.  
  5. const container = document.querySelector('#<?php echo $id; ?>');
  6.  
  7. inspector.setManagedWidget(container.querySelector('img'));
  1. inspector.reset();
SEE ALSO

BooleanInspector, NumberInspector, StringInspector, SelectInspector, OptionInspector, SelectionInspector, ColorInspector

Comments

Your comment:
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip help 2000

Enter a maximum of 2000 characters.
Improve the presentation of your text with the following formatting tags:
[p]paragraph[/p], [b]bold[/b], [i]italics[/i], [u]underline[/u], [s]strike[/s], [quote]citation[/quote], [pre]as is[/pre], [br]line break,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]command[/code], [code=language]source code in c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].