Advertisement
Guest User

Untitled

a guest
Jan 18th, 2016
237
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. console.log('foo');
  2. /** smart-crop.js
  3.  * A javascript library implementing content aware image cropping
  4.  *
  5.  * Copyright (C) 2014 Jonas Wagner
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining
  8.  * a copy of this software and associated documentation files (the
  9.  * "Software"), to deal in the Software without restriction, including
  10.  * without limitation the rights to use, copy, modify, merge, publish,
  11.  * distribute, sublicense, and/or sell copies of the Software, and to
  12.  * permit persons to whom the Software is furnished to do so, subject to
  13.  * the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice shall be
  16.  * included in all copies or substantial portions of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  19.  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21.  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  22.  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  23.  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  24.  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  */
  26.  
  27. (function(){
  28. "use strict";
  29.  
  30. function SmartCrop(options){
  31.    this.options = extend({}, SmartCrop.DEFAULTS, options);
  32. }
  33. SmartCrop.DEFAULTS = {
  34.     width: 0,
  35.     height: 0,
  36.     aspect: 0,
  37.     cropWidth: 0,
  38.     cropHeight: 0,
  39.     detailWeight: 0.2,
  40.     skinColor: [0.78, 0.57, 0.44],
  41.     skinBias: 0.01,
  42.     skinBrightnessMin: 0.2,
  43.     skinBrightnessMax: 1.0,
  44.     skinThreshold: 0.8,
  45.     skinWeight: 1.8,
  46.     saturationBrightnessMin: 0.05,
  47.     saturationBrightnessMax: 0.9,
  48.     saturationThreshold: 0.4,
  49.     saturationBias: 0.2,
  50.     saturationWeight: 0.3,
  51.     // step * minscale rounded down to the next power of two should be good
  52.     scoreDownSample: 8,
  53.     step: 8,
  54.     scaleStep: 0.1,
  55.     minScale: 0.9,
  56.     maxScale: 1.0,
  57.     edgeRadius: 0.4,
  58.     edgeWeight: -20.0,
  59.     outsideImportance: -0.5,
  60.     ruleOfThirds: true,
  61.     prescale: true,
  62.     canvasFactory: null,
  63.     debug: false
  64. };
  65. SmartCrop.crop = function(image, options, callback){
  66.     if(options.aspect){
  67.         options.width = options.aspect;
  68.         options.height = 1;
  69.     }
  70.  
  71.     // work around images scaled in css by drawing them onto a canvas
  72.     if(image.naturalWidth && (image.naturalWidth != image.width || image.naturalHeight != image.height)){
  73.         var c = new SmartCrop(options).canvas(image.naturalWidth, image.naturalHeight),
  74.             cctx = c.getContext('2d');
  75.         c.width = image.naturalWidth;
  76.         c.height = image.naturalHeight;
  77.         cctx.drawImage(image, 0, 0);
  78.         image = c;
  79.     }
  80.  
  81.     var scale = 1,
  82.         prescale = 1;
  83.     if(options.width && options.height) {
  84.         scale = min(image.width/options.width, image.height/options.height);
  85.         options.cropWidth = ~~(options.width * scale);
  86.         options.cropHeight = ~~(options.height * scale);
  87.         // img = 100x100, width = 95x95, scale = 100/95, 1/scale > min
  88.         // don't set minscale smaller than 1/scale
  89.         // -> don't pick crops that need upscaling
  90.         options.minScale = min(options.maxScale || SmartCrop.DEFAULTS.maxScale, max(1/scale, (options.minScale||SmartCrop.DEFAULTS.minScale)));
  91.     }
  92.     var smartCrop = new SmartCrop(options);
  93.     if(options.width && options.height) {
  94.         if(options.prescale !== false){
  95.             prescale = 1/scale/options.minScale;
  96.             if(prescale < 1) {
  97.                 var prescaledCanvas = smartCrop.canvas(image.width*prescale, image.height*prescale),
  98.                     ctx = prescaledCanvas.getContext('2d');
  99.                 ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, prescaledCanvas.width, prescaledCanvas.height);
  100.                 image = prescaledCanvas;
  101.                 smartCrop.options.cropWidth = ~~(options.cropWidth*prescale);
  102.                 smartCrop.options.cropHeight = ~~(options.cropHeight*prescale);
  103.             }
  104.             else {
  105.                 prescale = 1;
  106.             }
  107.         }
  108.     }
  109.     var result = smartCrop.analyse(image);
  110.     for(var i = 0, i_len = result.crops.length; i < i_len; i++) {
  111.         var crop = result.crops[i];
  112.         crop.x = ~~(crop.x/prescale);
  113.         crop.y = ~~(crop.y/prescale);
  114.         crop.width = ~~(crop.width/prescale);
  115.         crop.height = ~~(crop.height/prescale);
  116.     }
  117.     callback(result);
  118.     return result;
  119. };
  120. // check if all the dependencies are there
  121. SmartCrop.isAvailable = function(options){
  122.     try {
  123.         var s = new this(options),
  124.             c = s.canvas(16, 16);
  125.         return typeof c.getContext === 'function';
  126.     }
  127.     catch(e){
  128.         return false;
  129.     }
  130. };
  131. SmartCrop.prototype = {
  132.     canvas: function(w, h){
  133.         if(this.options.canvasFactory !== null){
  134.             return this.options.canvasFactory(w, h);
  135.         }
  136.         var c = document.createElement('canvas');
  137.         c.width = w;
  138.         c.height = h;
  139.         return c;
  140.     },
  141.     edgeDetect: function(i, o){
  142.         var id = i.data,
  143.             od = o.data,
  144.             w = i.width,
  145.             h = i.height;
  146.         for(var y = 0; y < h; y++) {
  147.             for(var x = 0; x < w; x++) {
  148.                 var p = (y*w+x)*4,
  149.                     lightness;
  150.                 if(x === 0 || x >= w-1 || y === 0 || y >= h-1){
  151.                     lightness = sample(id, p);
  152.                 }
  153.                 else {
  154.                     lightness = sample(id, p)*4 - sample(id, p-w*4) - sample(id, p-4) - sample(id, p+4) - sample(id, p+w*4);
  155.                 }
  156.                 od[p+1] = lightness;
  157.             }
  158.         }
  159.     },
  160.     skinDetect: function(i, o){
  161.         var id = i.data,
  162.             od = o.data,
  163.             w = i.width,
  164.             h = i.height,
  165.             options = this.options;
  166.         for(var y = 0; y < h; y++) {
  167.             for(var x = 0; x < w; x++) {
  168.                 var p = (y*w+x)*4,
  169.                     lightness = cie(id[p], id[p+1], id[p+2])/255,
  170.                     skin = this.skinColor(id[p], id[p+1], id[p+2]);
  171.                 if(skin > options.skinThreshold && lightness >= options.skinBrightnessMin && lightness <= options.skinBrightnessMax){
  172.                     od[p] = (skin-options.skinThreshold)*(255/(1-options.skinThreshold));
  173.                 }
  174.                 else {
  175.                     od[p] = 0;
  176.                 }
  177.             }
  178.         }
  179.     },
  180.     saturationDetect: function(i, o){
  181.         var id = i.data,
  182.             od = o.data,
  183.             w = i.width,
  184.             h = i.height,
  185.             options = this.options;
  186.         for(var y = 0; y < h; y++) {
  187.             for(var x = 0; x < w; x++) {
  188.                 var p = (y*w+x)*4,
  189.                     lightness = cie(id[p], id[p+1], id[p+2])/255,
  190.                     sat = saturation(id[p], id[p+1], id[p+2]);
  191.                 if(sat > options.saturationThreshold && lightness >= options.saturationBrightnessMin && lightness <= options.saturationBrightnessMax){
  192.                     od[p+2] = (sat-options.saturationThreshold)*(255/(1-options.saturationThreshold));
  193.                 }
  194.                 else {
  195.                     od[p+2] = 0;
  196.                 }
  197.             }
  198.         }
  199.     },
  200.     crops: function(image){
  201.         var crops = [],
  202.             width = image.width,
  203.             height = image.height,
  204.             options = this.options,
  205.             minDimension = min(width, height),
  206.             cropWidth = options.cropWidth || minDimension,
  207.             cropHeight = options.cropHeight || minDimension;
  208.         for(var scale = options.maxScale; scale >= options.minScale; scale -= options.scaleStep){
  209.             for(var y = 0; y+cropHeight*scale <= height; y+=options.step) {
  210.                 for(var x = 0; x+cropWidth*scale <= width; x+=options.step) {
  211.                     crops.push({
  212.                         x: x,
  213.                         y: y,
  214.                         width: cropWidth*scale,
  215.                         height: cropHeight*scale
  216.                     });
  217.                 }
  218.             }
  219.         }
  220.         return crops;
  221.     },
  222.     score: function(output, crop){
  223.         var score = {
  224.                 detail: 0,
  225.                 saturation: 0,
  226.                 skin: 0,
  227.                 total: 0
  228.             },
  229.             options = this.options,
  230.             od = output.data,
  231.             downSample = options.scoreDownSample,
  232.             invDownSample = 1/downSample,
  233.             outputHeightDownSample = output.height*downSample,
  234.             outputWidthDownSample = output.width*downSample,
  235.             outputWidth = output.width;
  236.         for(var y = 0; y < outputHeightDownSample; y+=downSample) {
  237.             for(var x = 0; x < outputWidthDownSample; x+=downSample) {
  238.                 var p = (~~(y*invDownSample)*outputWidth+~~(x*invDownSample))*4,
  239.                     importance = this.importance(crop, x, y),
  240.                     detail = od[p+1]/255;
  241.                 score.skin += od[p]/255*(detail+options.skinBias)*importance;
  242.                 score.detail += detail*importance;
  243.                 score.saturation += od[p+2]/255*(detail+options.saturationBias)*importance;
  244.             }
  245.  
  246.         }
  247.         score.total = (score.detail*options.detailWeight + score.skin*options.skinWeight + score.saturation*options.saturationWeight)/crop.width/crop.height;
  248.         return score;
  249.     },
  250.     importance: function(crop, x, y){
  251.         var options = this.options;
  252.  
  253.         if (crop.x > x || x >= crop.x+crop.width || crop.y > y || y >= crop.y+crop.height) return options.outsideImportance;
  254.         x = (x-crop.x)/crop.width;
  255.         y = (y-crop.y)/crop.height;
  256.         var px = abs(0.5-x)*2,
  257.             py = abs(0.5-y)*2,
  258.             // distance from edge
  259.             dx = Math.max(px-1.0+options.edgeRadius, 0),
  260.             dy = Math.max(py-1.0+options.edgeRadius, 0),
  261.             d = (dx*dx+dy*dy)*options.edgeWeight;
  262.         var s = 1.41-sqrt(px*px+py*py);
  263.         if(options.ruleOfThirds){
  264.             s += (Math.max(0, s+d+0.5)*1.2)*(thirds(px)+thirds(py));
  265.         }
  266.         return s+d;
  267.     },
  268.     skinColor: function(r, g, b){
  269.         var mag = sqrt(r*r+g*g+b*b),
  270.             options = this.options,
  271.             rd = (r/mag-options.skinColor[0]),
  272.             gd = (g/mag-options.skinColor[1]),
  273.             bd = (b/mag-options.skinColor[2]),
  274.             d = sqrt(rd*rd+gd*gd+bd*bd);
  275.             return 1-d;
  276.     },
  277.     analyse: function(image){
  278.         var result = {},
  279.             options = this.options,
  280.             canvas = this.canvas(image.width, image.height),
  281.             ctx = canvas.getContext('2d');
  282.         ctx.drawImage(image, 0, 0);
  283.         var input = ctx.getImageData(0, 0, canvas.width, canvas.height),
  284.             output = ctx.getImageData(0, 0, canvas.width, canvas.height);
  285.         this.edgeDetect(input, output);
  286.         this.skinDetect(input, output);
  287.         this.saturationDetect(input, output);
  288.  
  289.         var scoreCanvas = this.canvas(ceil(image.width/options.scoreDownSample), ceil(image.height/options.scoreDownSample)),
  290.             scoreCtx = scoreCanvas.getContext('2d');
  291.  
  292.         ctx.putImageData(output, 0, 0);
  293.         scoreCtx.drawImage(canvas, 0, 0, canvas.width, canvas.height, 0, 0, scoreCanvas.width, scoreCanvas.height);
  294.  
  295.         var scoreOutput = scoreCtx.getImageData(0, 0, scoreCanvas.width, scoreCanvas.height);
  296.  
  297.         var topScore = -Infinity,
  298.             topCrop = null,
  299.             crops = this.crops(image);
  300.  
  301.         for(var i = 0, i_len = crops.length; i < i_len; i++) {
  302.             var crop = crops[i];
  303.             crop.score = this.score(scoreOutput, crop);
  304.             if(crop.score.total > topScore){
  305.                 topCrop = crop;
  306.                 topScore = crop.score.total;
  307.             }
  308.  
  309.         }
  310.  
  311.         result.crops = crops;
  312.         result.topCrop = topCrop;
  313.  
  314.         if(options.debug && topCrop){
  315.             ctx.fillStyle = 'rgba(255, 0, 0, 0.1)';
  316.             ctx.fillRect(topCrop.x, topCrop.y, topCrop.width, topCrop.height);
  317.             for (var y = 0; y < output.height; y++) {
  318.                 for (var x = 0; x < output.width; x++) {
  319.                     var p = (y * output.width + x) * 4;
  320.                     var importance = this.importance(topCrop, x, y);
  321.                     if (importance > 0) {
  322.                         output.data[p + 1] += importance * 32;
  323.                     }
  324.  
  325.                     if (importance < 0) {
  326.                         output.data[p] += importance * -64;
  327.                     }
  328.                     output.data[p + 3] = 255;
  329.                 }
  330.             }
  331.             ctx.putImageData(output, 0, 0);
  332.             ctx.strokeStyle = 'rgba(255, 0, 0, 0.8)';
  333.             ctx.strokeRect(topCrop.x, topCrop.y, topCrop.width, topCrop.height);
  334.             result.debugCanvas = canvas;
  335.         }
  336.         return result;
  337.     }
  338. };
  339.  
  340. // aliases and helpers
  341. var min = Math.min,
  342.     max = Math.max,
  343.     abs = Math.abs,
  344.     ceil = Math.ceil,
  345.     sqrt = Math.sqrt;
  346.  
  347. function extend(o){
  348.     for(var i = 1, i_len = arguments.length; i < i_len; i++) {
  349.         var arg = arguments[i];
  350.         if(arg){
  351.             for(var name in arg){
  352.                 o[name] = arg[name];
  353.             }
  354.         }
  355.     }
  356.     return o;
  357. }
  358.  
  359. // gets value in the range of [0, 1] where 0 is the center of the pictures
  360. // returns weight of rule of thirds [0, 1]
  361. function thirds(x){
  362.     x = ((x-(1/3)+1.0)%2.0*0.5-0.5)*16;
  363.     return Math.max(1.0-x*x, 0.0);
  364. }
  365.  
  366. function cie(r, g, b){
  367.     return 0.5126*b + 0.7152*g + 0.0722*r;
  368. }
  369. function sample(id, p) {
  370.     return cie(id[p], id[p+1], id[p+2]);
  371. }
  372. function saturation(r, g, b){
  373.     var maximum = max(r/255, g/255, b/255), minumum = min(r/255, g/255, b/255);
  374.     if(maximum === minumum){
  375.         return 0;
  376.     }
  377.     var l = (maximum + minumum) / 2,
  378.         d = maximum-minumum;
  379.     return l > 0.5 ? d/(2-maximum-minumum) : d/(maximum+minumum);
  380. }
  381.  
  382. // amd
  383. if (typeof define !== 'undefined' && define.amd) define(function(){return SmartCrop;});
  384. //common js
  385. if (typeof exports !== 'undefined') exports.SmartCrop = SmartCrop;
  386. // browser
  387. else if (typeof navigator !== 'undefined') window.SmartCrop = SmartCrop;
  388. // nodejs
  389. if (typeof module !== 'undefined') {
  390.     module.exports = SmartCrop;
  391. }
  392. })();
  393.  
  394.  
  395.  
  396. /**
  397.  * @licence GNU GPL v2+
  398.  * @author Jonas Kress
  399.  */
  400.  
  401. (function( wb, mw, $, SmartCrop ) {
  402.     'use strict';
  403.  
  404.     /**
  405.      * Offers access to the page image
  406.      *
  407.      * Uses pageimages and pageprops Api endpoints to retrieve the image URL
  408.      *
  409.      * @constructor
  410.      *
  411.      * @param {int} width
  412.      * @param {int} height
  413.      */
  414.     var SELF = wb.PageImage = function PageImage( width, height ) {
  415.         if ( width ) {
  416.             this._width = width;
  417.         }
  418.         if ( height ) {
  419.             this._height = height;
  420.         }
  421.     };
  422.  
  423.     SELF.prototype._width = 200;
  424.     SELF.prototype._height = 200;
  425.  
  426.     SELF.prototype._thumbnailSize = 900;
  427.     SELF.prototype._minScale = 1;
  428.     SELF.prototype._crossOriginXmlUrl = 'https://upload.wikimedia.org/crossdomain.xml';
  429.  
  430.     /**
  431.      * Returns the page image as DOM element
  432.      * @return {Object} jQuery.Promise Resolved after loading and cropping of image is done
  433.      *         returning a DOM element.
  434.      */
  435.     SELF.prototype.getPageImage = function() {
  436.         var deferred = $.Deferred(),
  437.             self = this;
  438.  
  439.         self._getImageUrl().done( function( url, referenceUrl ){
  440.             self._loadImage( url ).done(
  441.                 function( image ) {
  442.                     self._getSmartCrop( image ).done(function( crop ) {
  443.                         deferred.resolve(self._getMaskedImage( image, crop, referenceUrl ));
  444.                     });
  445.                 });
  446.         } );
  447.  
  448.         return deferred.promise();
  449.     };
  450.  
  451.     /**
  452.      * @private
  453.      **/
  454.     SELF.prototype._loadImage = function( url ) {
  455.         var deferred = $.Deferred();
  456.  
  457.         var image = new Image();
  458.         image.onload = function() {
  459.             deferred.resolve( image );
  460.         };
  461.         image.crossOrigin = this._crossOriginXmlUrl;
  462.         image.src = url;
  463.  
  464.         return deferred.promise();
  465.     };
  466.  
  467.     /**
  468.      * @private
  469.      **/
  470.     SELF.prototype._getSmartCrop = function( image ) {
  471.         var deferred = $.Deferred();
  472.  
  473.         SmartCrop.crop( image, {
  474.             width : this._width,
  475.             height : this._height,
  476.             minScale: this._minScale,
  477.         }, function( result ) {
  478.             deferred.resolve( result.topCrop );
  479.         });
  480.  
  481.         return deferred.promise();
  482.     };
  483.  
  484.     /**
  485.      * @private
  486.      **/
  487.     SELF.prototype._getMaskedImage = function( image, crop, ref ) {
  488.  
  489.         var canvas = $('<canvas/>')[0], ctx = canvas.getContext('2d');
  490.  
  491.         if( ref ){
  492.             $(canvas).data( 'ref', ref );
  493.         }
  494.  
  495.         canvas.width = this._width;
  496.         canvas.height = this._height;
  497.         ctx.drawImage( image, crop.x, crop.y, crop.width, crop.height, 0, 0,
  498.                 canvas.width, canvas.height );
  499.  
  500.         return canvas;
  501.     };
  502.  
  503.     /**
  504.      * @private
  505.      **/
  506.     SELF.prototype._getImageUrl = function() {
  507.         var deferred = $.Deferred(),
  508.             self = this;
  509.  
  510.         mw.loader.using( 'mediawiki.api', function() {
  511.             ( new mw.Api()).get( {
  512.                 action : 'query',
  513.                 prop : 'pageimages|pageprops',
  514.                 piprop: 'thumbnail',
  515.                 pithumbsize: self._thumbnailSize,
  516.                 titles: mw.config.get( 'wgPageName' )
  517.             } ).done( function( data ) {
  518.                 var page = data.query.pages[Object.keys( data.query.pages )[0]];
  519.                 if( page.thumbnail ){
  520.                     deferred.resolve( page.thumbnail.source,
  521.                             page.pageprops.page_image );
  522.                 }
  523.  
  524.             });
  525.         });
  526.  
  527.         return deferred.promise();
  528.     };
  529.  
  530. }(wikibase, mw, jQuery, SmartCrop));
  531.  
  532.  
  533.         var pageImage = new wikibase.PageImage(365, 365);
  534.  
  535.         var div = $('<div/>');
  536.         $('.wikibase-entityview-side').prepend(div);
  537.         pageImage.getPageImage().done(function( element ){
  538.  
  539.              div.append(element) ;
  540.         });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement