Total Complexity | 688 |
Complexity/F | 1.51 |
Lines of Code | 3653 |
Function Count | 457 |
Duplicated Lines | 369 |
Ratio | 10.1 % |
Changes | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like public/js/tinymce/plugins/imagetools/plugin.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | (function () { |
||
2 | var imagetools = (function () { |
||
|
|||
3 | 'use strict'; |
||
4 | |||
5 | var Cell = function (initial) { |
||
6 | var value = initial; |
||
7 | var get = function () { |
||
8 | return value; |
||
9 | }; |
||
10 | var set = function (v) { |
||
11 | value = v; |
||
12 | }; |
||
13 | var clone = function () { |
||
14 | return Cell(get()); |
||
15 | }; |
||
16 | return { |
||
17 | get: get, |
||
18 | set: set, |
||
19 | clone: clone |
||
20 | }; |
||
21 | }; |
||
22 | |||
23 | var global = tinymce.util.Tools.resolve('tinymce.PluginManager'); |
||
24 | |||
25 | var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools'); |
||
26 | |||
27 | function create(width, height) { |
||
28 | return resize(document.createElement('canvas'), width, height); |
||
29 | } |
||
30 | function clone(canvas) { |
||
31 | var tCanvas, ctx; |
||
32 | tCanvas = create(canvas.width, canvas.height); |
||
33 | ctx = get2dContext(tCanvas); |
||
34 | ctx.drawImage(canvas, 0, 0); |
||
35 | return tCanvas; |
||
36 | } |
||
37 | function get2dContext(canvas) { |
||
38 | return canvas.getContext('2d'); |
||
39 | } |
||
40 | function get3dContext(canvas) { |
||
41 | var gl = null; |
||
42 | try { |
||
43 | gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); |
||
44 | } catch (e) { |
||
45 | } |
||
46 | if (!gl) { |
||
47 | gl = null; |
||
48 | } |
||
49 | return gl; |
||
50 | } |
||
51 | function resize(canvas, width, height) { |
||
52 | canvas.width = width; |
||
53 | canvas.height = height; |
||
54 | return canvas; |
||
55 | } |
||
56 | var Canvas = { |
||
57 | create: create, |
||
58 | clone: clone, |
||
59 | resize: resize, |
||
60 | get2dContext: get2dContext, |
||
61 | get3dContext: get3dContext |
||
62 | }; |
||
63 | |||
64 | function getWidth(image) { |
||
65 | return image.naturalWidth || image.width; |
||
66 | } |
||
67 | function getHeight(image) { |
||
68 | return image.naturalHeight || image.height; |
||
69 | } |
||
70 | var ImageSize = { |
||
71 | getWidth: getWidth, |
||
72 | getHeight: getHeight |
||
73 | }; |
||
74 | |||
75 | View Code Duplication | var promise = function () { |
|
76 | var Promise = function (fn) { |
||
77 | if (typeof this !== 'object') |
||
78 | throw new TypeError('Promises must be constructed via new'); |
||
79 | if (typeof fn !== 'function') |
||
80 | throw new TypeError('not a function'); |
||
81 | this._state = null; |
||
82 | this._value = null; |
||
83 | this._deferreds = []; |
||
84 | doResolve(fn, bind(resolve, this), bind(reject, this)); |
||
85 | }; |
||
86 | var asap = Promise.immediateFn || typeof window.setImmediate === 'function' && window.setImmediate || function (fn) { |
||
87 | setTimeout(fn, 1); |
||
88 | }; |
||
89 | function bind(fn, thisArg) { |
||
90 | return function () { |
||
91 | fn.apply(thisArg, arguments); |
||
92 | }; |
||
93 | } |
||
94 | var isArray = Array.isArray || function (value) { |
||
95 | return Object.prototype.toString.call(value) === '[object Array]'; |
||
96 | }; |
||
97 | function handle(deferred) { |
||
98 | var me = this; |
||
99 | if (this._state === null) { |
||
100 | this._deferreds.push(deferred); |
||
101 | return; |
||
102 | } |
||
103 | asap(function () { |
||
104 | var cb = me._state ? deferred.onFulfilled : deferred.onRejected; |
||
105 | if (cb === null) { |
||
106 | (me._state ? deferred.resolve : deferred.reject)(me._value); |
||
107 | return; |
||
108 | } |
||
109 | var ret; |
||
110 | try { |
||
111 | ret = cb(me._value); |
||
112 | } catch (e) { |
||
113 | deferred.reject(e); |
||
114 | return; |
||
115 | } |
||
116 | deferred.resolve(ret); |
||
117 | }); |
||
118 | } |
||
119 | function resolve(newValue) { |
||
120 | try { |
||
121 | if (newValue === this) |
||
122 | throw new TypeError('A promise cannot be resolved with itself.'); |
||
123 | if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { |
||
124 | var then = newValue.then; |
||
125 | if (typeof then === 'function') { |
||
126 | doResolve(bind(then, newValue), bind(resolve, this), bind(reject, this)); |
||
127 | return; |
||
128 | } |
||
129 | } |
||
130 | this._state = true; |
||
131 | this._value = newValue; |
||
132 | finale.call(this); |
||
133 | } catch (e) { |
||
134 | reject.call(this, e); |
||
135 | } |
||
136 | } |
||
137 | function reject(newValue) { |
||
138 | this._state = false; |
||
139 | this._value = newValue; |
||
140 | finale.call(this); |
||
141 | } |
||
142 | function finale() { |
||
143 | for (var i = 0, len = this._deferreds.length; i < len; i++) { |
||
144 | handle.call(this, this._deferreds[i]); |
||
145 | } |
||
146 | this._deferreds = null; |
||
147 | } |
||
148 | function Handler(onFulfilled, onRejected, resolve, reject) { |
||
149 | this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; |
||
150 | this.onRejected = typeof onRejected === 'function' ? onRejected : null; |
||
151 | this.resolve = resolve; |
||
152 | this.reject = reject; |
||
153 | } |
||
154 | function doResolve(fn, onFulfilled, onRejected) { |
||
155 | var done = false; |
||
156 | try { |
||
157 | fn(function (value) { |
||
158 | if (done) |
||
159 | return; |
||
160 | done = true; |
||
161 | onFulfilled(value); |
||
162 | }, function (reason) { |
||
163 | if (done) |
||
164 | return; |
||
165 | done = true; |
||
166 | onRejected(reason); |
||
167 | }); |
||
168 | } catch (ex) { |
||
169 | if (done) |
||
170 | return; |
||
171 | done = true; |
||
172 | onRejected(ex); |
||
173 | } |
||
174 | } |
||
175 | Promise.prototype['catch'] = function (onRejected) { |
||
176 | return this.then(null, onRejected); |
||
177 | }; |
||
178 | Promise.prototype.then = function (onFulfilled, onRejected) { |
||
179 | var me = this; |
||
180 | return new Promise(function (resolve, reject) { |
||
181 | handle.call(me, new Handler(onFulfilled, onRejected, resolve, reject)); |
||
182 | }); |
||
183 | }; |
||
184 | Promise.all = function () { |
||
185 | var args = Array.prototype.slice.call(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments); |
||
186 | return new Promise(function (resolve, reject) { |
||
187 | if (args.length === 0) |
||
188 | return resolve([]); |
||
189 | var remaining = args.length; |
||
190 | function res(i, val) { |
||
191 | try { |
||
192 | if (val && (typeof val === 'object' || typeof val === 'function')) { |
||
193 | var then = val.then; |
||
194 | if (typeof then === 'function') { |
||
195 | then.call(val, function (val) { |
||
196 | res(i, val); |
||
197 | }, reject); |
||
198 | return; |
||
199 | } |
||
200 | } |
||
201 | args[i] = val; |
||
202 | if (--remaining === 0) { |
||
203 | resolve(args); |
||
204 | } |
||
205 | } catch (ex) { |
||
206 | reject(ex); |
||
207 | } |
||
208 | } |
||
209 | for (var i = 0; i < args.length; i++) { |
||
210 | res(i, args[i]); |
||
211 | } |
||
212 | }); |
||
213 | }; |
||
214 | Promise.resolve = function (value) { |
||
215 | if (value && typeof value === 'object' && value.constructor === Promise) { |
||
216 | return value; |
||
217 | } |
||
218 | return new Promise(function (resolve) { |
||
219 | resolve(value); |
||
220 | }); |
||
221 | }; |
||
222 | Promise.reject = function (value) { |
||
223 | return new Promise(function (resolve, reject) { |
||
224 | reject(value); |
||
225 | }); |
||
226 | }; |
||
227 | Promise.race = function (values) { |
||
228 | return new Promise(function (resolve, reject) { |
||
229 | for (var i = 0, len = values.length; i < len; i++) { |
||
230 | values[i].then(resolve, reject); |
||
231 | } |
||
232 | }); |
||
233 | }; |
||
234 | return Promise; |
||
235 | }; |
||
236 | var Promise = window.Promise ? window.Promise : promise(); |
||
237 | |||
238 | var constant = function (value) { |
||
239 | return function () { |
||
240 | return value; |
||
241 | }; |
||
242 | }; |
||
243 | View Code Duplication | function curry(fn) { |
|
244 | var initialArgs = []; |
||
245 | for (var _i = 1; _i < arguments.length; _i++) { |
||
246 | initialArgs[_i - 1] = arguments[_i]; |
||
247 | } |
||
248 | return function () { |
||
249 | var restArgs = []; |
||
250 | for (var _i = 0; _i < arguments.length; _i++) { |
||
251 | restArgs[_i] = arguments[_i]; |
||
252 | } |
||
253 | var all = initialArgs.concat(restArgs); |
||
254 | return fn.apply(null, all); |
||
255 | }; |
||
256 | } |
||
257 | var never = constant(false); |
||
258 | var always = constant(true); |
||
259 | |||
260 | var never$1 = never; |
||
261 | var always$1 = always; |
||
262 | var none = function () { |
||
263 | return NONE; |
||
264 | }; |
||
265 | View Code Duplication | var NONE = function () { |
|
266 | var eq = function (o) { |
||
267 | return o.isNone(); |
||
268 | }; |
||
269 | var call$$1 = function (thunk) { |
||
270 | return thunk(); |
||
271 | }; |
||
272 | var id = function (n) { |
||
273 | return n; |
||
274 | }; |
||
275 | var noop$$1 = function () { |
||
276 | }; |
||
277 | var nul = function () { |
||
278 | return null; |
||
279 | }; |
||
280 | var undef = function () { |
||
281 | return undefined; |
||
282 | }; |
||
283 | var me = { |
||
284 | fold: function (n, s) { |
||
285 | return n(); |
||
286 | }, |
||
287 | is: never$1, |
||
288 | isSome: never$1, |
||
289 | isNone: always$1, |
||
290 | getOr: id, |
||
291 | getOrThunk: call$$1, |
||
292 | getOrDie: function (msg) { |
||
293 | throw new Error(msg || 'error: getOrDie called on none.'); |
||
294 | }, |
||
295 | getOrNull: nul, |
||
296 | getOrUndefined: undef, |
||
297 | or: id, |
||
298 | orThunk: call$$1, |
||
299 | map: none, |
||
300 | ap: none, |
||
301 | each: noop$$1, |
||
302 | bind: none, |
||
303 | flatten: none, |
||
304 | exists: never$1, |
||
305 | forall: always$1, |
||
306 | filter: none, |
||
307 | equals: eq, |
||
308 | equals_: eq, |
||
309 | toArray: function () { |
||
310 | return []; |
||
311 | }, |
||
312 | toString: constant('none()') |
||
313 | }; |
||
314 | if (Object.freeze) |
||
315 | Object.freeze(me); |
||
316 | return me; |
||
317 | }(); |
||
318 | View Code Duplication | var some = function (a) { |
|
319 | var constant_a = function () { |
||
320 | return a; |
||
321 | }; |
||
322 | var self = function () { |
||
323 | return me; |
||
324 | }; |
||
325 | var map = function (f) { |
||
326 | return some(f(a)); |
||
327 | }; |
||
328 | var bind = function (f) { |
||
329 | return f(a); |
||
330 | }; |
||
331 | var me = { |
||
332 | fold: function (n, s) { |
||
333 | return s(a); |
||
334 | }, |
||
335 | is: function (v) { |
||
336 | return a === v; |
||
337 | }, |
||
338 | isSome: always$1, |
||
339 | isNone: never$1, |
||
340 | getOr: constant_a, |
||
341 | getOrThunk: constant_a, |
||
342 | getOrDie: constant_a, |
||
343 | getOrNull: constant_a, |
||
344 | getOrUndefined: constant_a, |
||
345 | or: self, |
||
346 | orThunk: self, |
||
347 | map: map, |
||
348 | ap: function (optfab) { |
||
349 | return optfab.fold(none, function (fab) { |
||
350 | return some(fab(a)); |
||
351 | }); |
||
352 | }, |
||
353 | each: function (f) { |
||
354 | f(a); |
||
355 | }, |
||
356 | bind: bind, |
||
357 | flatten: constant_a, |
||
358 | exists: bind, |
||
359 | forall: bind, |
||
360 | filter: function (f) { |
||
361 | return f(a) ? me : NONE; |
||
362 | }, |
||
363 | equals: function (o) { |
||
364 | return o.is(a); |
||
365 | }, |
||
366 | equals_: function (o, elementEq) { |
||
367 | return o.fold(never$1, function (b) { |
||
368 | return elementEq(a, b); |
||
369 | }); |
||
370 | }, |
||
371 | toArray: function () { |
||
372 | return [a]; |
||
373 | }, |
||
374 | toString: function () { |
||
375 | return 'some(' + a + ')'; |
||
376 | } |
||
377 | }; |
||
378 | return me; |
||
379 | }; |
||
380 | var from = function (value) { |
||
381 | return value === null || value === undefined ? NONE : some(value); |
||
382 | }; |
||
383 | var Option = { |
||
384 | some: some, |
||
385 | none: none, |
||
386 | from: from |
||
387 | }; |
||
388 | |||
389 | var Global = typeof window !== 'undefined' ? window : Function('return this;')(); |
||
390 | |||
391 | View Code Duplication | var path = function (parts, scope) { |
|
392 | var o = scope !== undefined && scope !== null ? scope : Global; |
||
393 | for (var i = 0; i < parts.length && o !== undefined && o !== null; ++i) |
||
394 | o = o[parts[i]]; |
||
395 | return o; |
||
396 | }; |
||
397 | var resolve = function (p, scope) { |
||
398 | var parts = p.split('.'); |
||
399 | return path(parts, scope); |
||
400 | }; |
||
401 | |||
402 | var unsafe = function (name, scope) { |
||
403 | return resolve(name, scope); |
||
404 | }; |
||
405 | var getOrDie = function (name, scope) { |
||
406 | var actual = unsafe(name, scope); |
||
407 | if (actual === undefined || actual === null) |
||
408 | throw name + ' not available on this browser'; |
||
409 | return actual; |
||
410 | }; |
||
411 | var Global$1 = { getOrDie: getOrDie }; |
||
412 | |||
413 | function Blob (parts, properties) { |
||
414 | var f = Global$1.getOrDie('Blob'); |
||
415 | return new f(parts, properties); |
||
416 | } |
||
417 | |||
418 | function FileReader () { |
||
419 | var f = Global$1.getOrDie('FileReader'); |
||
420 | return new f(); |
||
421 | } |
||
422 | |||
423 | function Uint8Array (arr) { |
||
424 | var f = Global$1.getOrDie('Uint8Array'); |
||
425 | return new f(arr); |
||
426 | } |
||
427 | |||
428 | var requestAnimationFrame = function (callback) { |
||
429 | var f = Global$1.getOrDie('requestAnimationFrame'); |
||
430 | f(callback); |
||
431 | }; |
||
432 | var atob = function (base64) { |
||
433 | var f = Global$1.getOrDie('atob'); |
||
434 | return f(base64); |
||
435 | }; |
||
436 | var Window = { |
||
437 | atob: atob, |
||
438 | requestAnimationFrame: requestAnimationFrame |
||
439 | }; |
||
440 | |||
441 | function imageToBlob(image) { |
||
442 | var src = image.src; |
||
443 | if (src.indexOf('data:') === 0) { |
||
444 | return dataUriToBlob(src); |
||
445 | } |
||
446 | return anyUriToBlob(src); |
||
447 | } |
||
448 | View Code Duplication | function blobToImage(blob) { |
|
449 | return new Promise(function (resolve, reject) { |
||
450 | var blobUrl = URL.createObjectURL(blob); |
||
451 | var image = new Image(); |
||
452 | var removeListeners = function () { |
||
453 | image.removeEventListener('load', loaded); |
||
454 | image.removeEventListener('error', error); |
||
455 | }; |
||
456 | function loaded() { |
||
457 | removeListeners(); |
||
458 | resolve(image); |
||
459 | } |
||
460 | function error() { |
||
461 | removeListeners(); |
||
462 | reject('Unable to load data of type ' + blob.type + ': ' + blobUrl); |
||
463 | } |
||
464 | image.addEventListener('load', loaded); |
||
465 | image.addEventListener('error', error); |
||
466 | image.src = blobUrl; |
||
467 | if (image.complete) { |
||
468 | loaded(); |
||
469 | } |
||
470 | }); |
||
471 | } |
||
472 | View Code Duplication | function anyUriToBlob(url) { |
|
473 | return new Promise(function (resolve, reject) { |
||
474 | var xhr = new XMLHttpRequest(); |
||
475 | xhr.open('GET', url, true); |
||
476 | xhr.responseType = 'blob'; |
||
477 | xhr.onload = function () { |
||
478 | if (this.status == 200) { |
||
479 | resolve(this.response); |
||
480 | } |
||
481 | }; |
||
482 | xhr.onerror = function () { |
||
483 | var _this = this; |
||
484 | var corsError = function () { |
||
485 | var obj = new Error('No access to download image'); |
||
486 | obj.code = 18; |
||
487 | obj.name = 'SecurityError'; |
||
488 | return obj; |
||
489 | }; |
||
490 | var genericError = function () { |
||
491 | return new Error('Error ' + _this.status + ' downloading image'); |
||
492 | }; |
||
493 | reject(this.status === 0 ? corsError() : genericError()); |
||
494 | }; |
||
495 | xhr.send(); |
||
496 | }); |
||
497 | } |
||
498 | View Code Duplication | function dataUriToBlobSync(uri) { |
|
499 | var data = uri.split(','); |
||
500 | var matches = /data:([^;]+)/.exec(data[0]); |
||
501 | if (!matches) |
||
502 | return Option.none(); |
||
503 | var mimetype = matches[1]; |
||
504 | var base64 = data[1]; |
||
505 | var sliceSize = 1024; |
||
506 | var byteCharacters = Window.atob(base64); |
||
507 | var bytesLength = byteCharacters.length; |
||
508 | var slicesCount = Math.ceil(bytesLength / sliceSize); |
||
509 | var byteArrays = new Array(slicesCount); |
||
510 | for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) { |
||
511 | var begin = sliceIndex * sliceSize; |
||
512 | var end = Math.min(begin + sliceSize, bytesLength); |
||
513 | var bytes = new Array(end - begin); |
||
514 | for (var offset = begin, i = 0; offset < end; ++i, ++offset) { |
||
515 | bytes[i] = byteCharacters[offset].charCodeAt(0); |
||
516 | } |
||
517 | byteArrays[sliceIndex] = Uint8Array(bytes); |
||
518 | } |
||
519 | return Option.some(Blob(byteArrays, { type: mimetype })); |
||
520 | } |
||
521 | function dataUriToBlob(uri) { |
||
522 | return new Promise(function (resolve, reject) { |
||
523 | dataUriToBlobSync(uri).fold(function () { |
||
524 | reject('uri is not base64: ' + uri); |
||
525 | }, resolve); |
||
526 | }); |
||
527 | } |
||
528 | function uriToBlob(url) { |
||
529 | if (url.indexOf('blob:') === 0) { |
||
530 | return anyUriToBlob(url); |
||
531 | } |
||
532 | if (url.indexOf('data:') === 0) { |
||
533 | return dataUriToBlob(url); |
||
534 | } |
||
535 | return null; |
||
536 | } |
||
537 | function canvasToBlob(canvas, type, quality) { |
||
538 | type = type || 'image/png'; |
||
539 | if (HTMLCanvasElement.prototype.toBlob) { |
||
540 | return new Promise(function (resolve) { |
||
541 | canvas.toBlob(function (blob) { |
||
542 | resolve(blob); |
||
543 | }, type, quality); |
||
544 | }); |
||
545 | } else { |
||
546 | return dataUriToBlob(canvas.toDataURL(type, quality)); |
||
547 | } |
||
548 | } |
||
549 | function canvasToDataURL(getCanvas, type, quality) { |
||
550 | type = type || 'image/png'; |
||
551 | return getCanvas.then(function (canvas) { |
||
552 | return canvas.toDataURL(type, quality); |
||
553 | }); |
||
554 | } |
||
555 | function blobToCanvas(blob) { |
||
556 | return blobToImage(blob).then(function (image) { |
||
557 | revokeImageUrl(image); |
||
558 | var context, canvas; |
||
559 | canvas = Canvas.create(ImageSize.getWidth(image), ImageSize.getHeight(image)); |
||
560 | context = Canvas.get2dContext(canvas); |
||
561 | context.drawImage(image, 0, 0); |
||
562 | return canvas; |
||
563 | }); |
||
564 | } |
||
565 | function blobToDataUri(blob) { |
||
566 | return new Promise(function (resolve) { |
||
567 | var reader = FileReader(); |
||
568 | reader.onloadend = function () { |
||
569 | resolve(reader.result); |
||
570 | }; |
||
571 | reader.readAsDataURL(blob); |
||
572 | }); |
||
573 | } |
||
574 | function blobToArrayBuffer(blob) { |
||
575 | return new Promise(function (resolve) { |
||
576 | var reader = FileReader(); |
||
577 | reader.onloadend = function () { |
||
578 | resolve(reader.result); |
||
579 | }; |
||
580 | reader.readAsArrayBuffer(blob); |
||
581 | }); |
||
582 | } |
||
583 | function blobToBase64(blob) { |
||
584 | return blobToDataUri(blob).then(function (dataUri) { |
||
585 | return dataUri.split(',')[1]; |
||
586 | }); |
||
587 | } |
||
588 | function revokeImageUrl(image) { |
||
589 | URL.revokeObjectURL(image.src); |
||
590 | } |
||
591 | var Conversions = { |
||
592 | blobToImage: blobToImage, |
||
593 | imageToBlob: imageToBlob, |
||
594 | blobToArrayBuffer: blobToArrayBuffer, |
||
595 | blobToDataUri: blobToDataUri, |
||
596 | blobToBase64: blobToBase64, |
||
597 | dataUriToBlobSync: dataUriToBlobSync, |
||
598 | canvasToBlob: canvasToBlob, |
||
599 | canvasToDataURL: canvasToDataURL, |
||
600 | blobToCanvas: blobToCanvas, |
||
601 | uriToBlob: uriToBlob |
||
602 | }; |
||
603 | |||
604 | var blobToImage$1 = function (image) { |
||
605 | return Conversions.blobToImage(image); |
||
606 | }; |
||
607 | var imageToBlob$1 = function (blob) { |
||
608 | return Conversions.imageToBlob(blob); |
||
609 | }; |
||
610 | var blobToDataUri$1 = function (blob) { |
||
611 | return Conversions.blobToDataUri(blob); |
||
612 | }; |
||
613 | var blobToBase64$1 = function (blob) { |
||
614 | return Conversions.blobToBase64(blob); |
||
615 | }; |
||
616 | var dataUriToBlobSync$1 = function (uri) { |
||
617 | return Conversions.dataUriToBlobSync(uri); |
||
618 | }; |
||
619 | var uriToBlob$1 = function (uri) { |
||
620 | return Option.from(Conversions.uriToBlob(uri)); |
||
621 | }; |
||
622 | var BlobConversions = { |
||
623 | blobToImage: blobToImage$1, |
||
624 | imageToBlob: imageToBlob$1, |
||
625 | blobToDataUri: blobToDataUri$1, |
||
626 | blobToBase64: blobToBase64$1, |
||
627 | dataUriToBlobSync: dataUriToBlobSync$1, |
||
628 | uriToBlob: uriToBlob$1 |
||
629 | }; |
||
630 | |||
631 | function create$1(getCanvas, blob, uri) { |
||
632 | var initialType = blob.type; |
||
633 | var getType = constant(initialType); |
||
634 | function toBlob() { |
||
635 | return Promise.resolve(blob); |
||
636 | } |
||
637 | function toDataURL() { |
||
638 | return uri; |
||
639 | } |
||
640 | function toBase64() { |
||
641 | return uri.split(',')[1]; |
||
642 | } |
||
643 | function toAdjustedBlob(type, quality) { |
||
644 | return getCanvas.then(function (canvas) { |
||
645 | return Conversions.canvasToBlob(canvas, type, quality); |
||
646 | }); |
||
647 | } |
||
648 | function toAdjustedDataURL(type, quality) { |
||
649 | return getCanvas.then(function (canvas) { |
||
650 | return Conversions.canvasToDataURL(canvas, type, quality); |
||
651 | }); |
||
652 | } |
||
653 | function toAdjustedBase64(type, quality) { |
||
654 | return toAdjustedDataURL(type, quality).then(function (dataurl) { |
||
655 | return dataurl.split(',')[1]; |
||
656 | }); |
||
657 | } |
||
658 | function toCanvas() { |
||
659 | return getCanvas.then(Canvas.clone); |
||
660 | } |
||
661 | return { |
||
662 | getType: getType, |
||
663 | toBlob: toBlob, |
||
664 | toDataURL: toDataURL, |
||
665 | toBase64: toBase64, |
||
666 | toAdjustedBlob: toAdjustedBlob, |
||
667 | toAdjustedDataURL: toAdjustedDataURL, |
||
668 | toAdjustedBase64: toAdjustedBase64, |
||
669 | toCanvas: toCanvas |
||
670 | }; |
||
671 | } |
||
672 | function fromBlob(blob) { |
||
673 | return Conversions.blobToDataUri(blob).then(function (uri) { |
||
674 | return create$1(Conversions.blobToCanvas(blob), blob, uri); |
||
675 | }); |
||
676 | } |
||
677 | function fromCanvas(canvas, type) { |
||
678 | return Conversions.canvasToBlob(canvas, type).then(function (blob) { |
||
679 | return create$1(Promise.resolve(canvas), blob, canvas.toDataURL()); |
||
680 | }); |
||
681 | } |
||
682 | function fromImage(image) { |
||
683 | return Conversions.imageToBlob(image).then(function (blob) { |
||
684 | return fromBlob(blob); |
||
685 | }); |
||
686 | } |
||
687 | var fromBlobAndUrlSync = function (blob, url) { |
||
688 | return create$1(Conversions.blobToCanvas(blob), blob, url); |
||
689 | }; |
||
690 | var ImageResult = { |
||
691 | fromBlob: fromBlob, |
||
692 | fromCanvas: fromCanvas, |
||
693 | fromImage: fromImage, |
||
694 | fromBlobAndUrlSync: fromBlobAndUrlSync |
||
695 | }; |
||
696 | |||
697 | function clamp(value, min, max) { |
||
698 | value = parseFloat(value); |
||
699 | if (value > max) { |
||
700 | value = max; |
||
701 | } else if (value < min) { |
||
702 | value = min; |
||
703 | } |
||
704 | return value; |
||
705 | } |
||
706 | function identity$1() { |
||
707 | return [ |
||
708 | 1, |
||
709 | 0, |
||
710 | 0, |
||
711 | 0, |
||
712 | 0, |
||
713 | 0, |
||
714 | 1, |
||
715 | 0, |
||
716 | 0, |
||
717 | 0, |
||
718 | 0, |
||
719 | 0, |
||
720 | 1, |
||
721 | 0, |
||
722 | 0, |
||
723 | 0, |
||
724 | 0, |
||
725 | 0, |
||
726 | 1, |
||
727 | 0, |
||
728 | 0, |
||
729 | 0, |
||
730 | 0, |
||
731 | 0, |
||
732 | 1 |
||
733 | ]; |
||
734 | } |
||
735 | var DELTA_INDEX = [ |
||
736 | 0, |
||
737 | 0.01, |
||
738 | 0.02, |
||
739 | 0.04, |
||
740 | 0.05, |
||
741 | 0.06, |
||
742 | 0.07, |
||
743 | 0.08, |
||
744 | 0.1, |
||
745 | 0.11, |
||
746 | 0.12, |
||
747 | 0.14, |
||
748 | 0.15, |
||
749 | 0.16, |
||
750 | 0.17, |
||
751 | 0.18, |
||
752 | 0.2, |
||
753 | 0.21, |
||
754 | 0.22, |
||
755 | 0.24, |
||
756 | 0.25, |
||
757 | 0.27, |
||
758 | 0.28, |
||
759 | 0.3, |
||
760 | 0.32, |
||
761 | 0.34, |
||
762 | 0.36, |
||
763 | 0.38, |
||
764 | 0.4, |
||
765 | 0.42, |
||
766 | 0.44, |
||
767 | 0.46, |
||
768 | 0.48, |
||
769 | 0.5, |
||
770 | 0.53, |
||
771 | 0.56, |
||
772 | 0.59, |
||
773 | 0.62, |
||
774 | 0.65, |
||
775 | 0.68, |
||
776 | 0.71, |
||
777 | 0.74, |
||
778 | 0.77, |
||
779 | 0.8, |
||
780 | 0.83, |
||
781 | 0.86, |
||
782 | 0.89, |
||
783 | 0.92, |
||
784 | 0.95, |
||
785 | 0.98, |
||
786 | 1, |
||
787 | 1.06, |
||
788 | 1.12, |
||
789 | 1.18, |
||
790 | 1.24, |
||
791 | 1.3, |
||
792 | 1.36, |
||
793 | 1.42, |
||
794 | 1.48, |
||
795 | 1.54, |
||
796 | 1.6, |
||
797 | 1.66, |
||
798 | 1.72, |
||
799 | 1.78, |
||
800 | 1.84, |
||
801 | 1.9, |
||
802 | 1.96, |
||
803 | 2, |
||
804 | 2.12, |
||
805 | 2.25, |
||
806 | 2.37, |
||
807 | 2.5, |
||
808 | 2.62, |
||
809 | 2.75, |
||
810 | 2.87, |
||
811 | 3, |
||
812 | 3.2, |
||
813 | 3.4, |
||
814 | 3.6, |
||
815 | 3.8, |
||
816 | 4, |
||
817 | 4.3, |
||
818 | 4.7, |
||
819 | 4.9, |
||
820 | 5, |
||
821 | 5.5, |
||
822 | 6, |
||
823 | 6.5, |
||
824 | 6.8, |
||
825 | 7, |
||
826 | 7.3, |
||
827 | 7.5, |
||
828 | 7.8, |
||
829 | 8, |
||
830 | 8.4, |
||
831 | 8.7, |
||
832 | 9, |
||
833 | 9.4, |
||
834 | 9.6, |
||
835 | 9.8, |
||
836 | 10 |
||
837 | ]; |
||
838 | function multiply(matrix1, matrix2) { |
||
839 | var i, j, k, val, col = [], out = new Array(10); |
||
840 | for (i = 0; i < 5; i++) { |
||
841 | for (j = 0; j < 5; j++) { |
||
842 | col[j] = matrix2[j + i * 5]; |
||
843 | } |
||
844 | for (j = 0; j < 5; j++) { |
||
845 | val = 0; |
||
846 | for (k = 0; k < 5; k++) { |
||
847 | val += matrix1[j + k * 5] * col[k]; |
||
848 | } |
||
849 | out[j + i * 5] = val; |
||
850 | } |
||
851 | } |
||
852 | return out; |
||
853 | } |
||
854 | function adjust(matrix, adjustValue) { |
||
855 | adjustValue = clamp(adjustValue, 0, 1); |
||
856 | return matrix.map(function (value, index) { |
||
857 | if (index % 6 === 0) { |
||
858 | value = 1 - (1 - value) * adjustValue; |
||
859 | } else { |
||
860 | value *= adjustValue; |
||
861 | } |
||
862 | return clamp(value, 0, 1); |
||
863 | }); |
||
864 | } |
||
865 | function adjustContrast(matrix, value) { |
||
866 | var x; |
||
867 | value = clamp(value, -1, 1); |
||
868 | value *= 100; |
||
869 | if (value < 0) { |
||
870 | x = 127 + value / 100 * 127; |
||
871 | } else { |
||
872 | x = value % 1; |
||
873 | if (x === 0) { |
||
874 | x = DELTA_INDEX[value]; |
||
875 | } else { |
||
876 | x = DELTA_INDEX[Math.floor(value)] * (1 - x) + DELTA_INDEX[Math.floor(value) + 1] * x; |
||
877 | } |
||
878 | x = x * 127 + 127; |
||
879 | } |
||
880 | return multiply(matrix, [ |
||
881 | x / 127, |
||
882 | 0, |
||
883 | 0, |
||
884 | 0, |
||
885 | 0.5 * (127 - x), |
||
886 | 0, |
||
887 | x / 127, |
||
888 | 0, |
||
889 | 0, |
||
890 | 0.5 * (127 - x), |
||
891 | 0, |
||
892 | 0, |
||
893 | x / 127, |
||
894 | 0, |
||
895 | 0.5 * (127 - x), |
||
896 | 0, |
||
897 | 0, |
||
898 | 0, |
||
899 | 1, |
||
900 | 0, |
||
901 | 0, |
||
902 | 0, |
||
903 | 0, |
||
904 | 0, |
||
905 | 1 |
||
906 | ]); |
||
907 | } |
||
908 | function adjustSaturation(matrix, value) { |
||
909 | var x, lumR, lumG, lumB; |
||
910 | value = clamp(value, -1, 1); |
||
911 | x = 1 + (value > 0 ? 3 * value : value); |
||
912 | lumR = 0.3086; |
||
913 | lumG = 0.6094; |
||
914 | lumB = 0.082; |
||
915 | return multiply(matrix, [ |
||
916 | lumR * (1 - x) + x, |
||
917 | lumG * (1 - x), |
||
918 | lumB * (1 - x), |
||
919 | 0, |
||
920 | 0, |
||
921 | lumR * (1 - x), |
||
922 | lumG * (1 - x) + x, |
||
923 | lumB * (1 - x), |
||
924 | 0, |
||
925 | 0, |
||
926 | lumR * (1 - x), |
||
927 | lumG * (1 - x), |
||
928 | lumB * (1 - x) + x, |
||
929 | 0, |
||
930 | 0, |
||
931 | 0, |
||
932 | 0, |
||
933 | 0, |
||
934 | 1, |
||
935 | 0, |
||
936 | 0, |
||
937 | 0, |
||
938 | 0, |
||
939 | 0, |
||
940 | 1 |
||
941 | ]); |
||
942 | } |
||
943 | function adjustHue(matrix, angle) { |
||
944 | var cosVal, sinVal, lumR, lumG, lumB; |
||
945 | angle = clamp(angle, -180, 180) / 180 * Math.PI; |
||
946 | cosVal = Math.cos(angle); |
||
947 | sinVal = Math.sin(angle); |
||
948 | lumR = 0.213; |
||
949 | lumG = 0.715; |
||
950 | lumB = 0.072; |
||
951 | return multiply(matrix, [ |
||
952 | lumR + cosVal * (1 - lumR) + sinVal * -lumR, |
||
953 | lumG + cosVal * -lumG + sinVal * -lumG, |
||
954 | lumB + cosVal * -lumB + sinVal * (1 - lumB), |
||
955 | 0, |
||
956 | 0, |
||
957 | lumR + cosVal * -lumR + sinVal * 0.143, |
||
958 | lumG + cosVal * (1 - lumG) + sinVal * 0.14, |
||
959 | lumB + cosVal * -lumB + sinVal * -0.283, |
||
960 | 0, |
||
961 | 0, |
||
962 | lumR + cosVal * -lumR + sinVal * -(1 - lumR), |
||
963 | lumG + cosVal * -lumG + sinVal * lumG, |
||
964 | lumB + cosVal * (1 - lumB) + sinVal * lumB, |
||
965 | 0, |
||
966 | 0, |
||
967 | 0, |
||
968 | 0, |
||
969 | 0, |
||
970 | 1, |
||
971 | 0, |
||
972 | 0, |
||
973 | 0, |
||
974 | 0, |
||
975 | 0, |
||
976 | 1 |
||
977 | ]); |
||
978 | } |
||
979 | function adjustBrightness(matrix, value) { |
||
980 | value = clamp(255 * value, -255, 255); |
||
981 | return multiply(matrix, [ |
||
982 | 1, |
||
983 | 0, |
||
984 | 0, |
||
985 | 0, |
||
986 | value, |
||
987 | 0, |
||
988 | 1, |
||
989 | 0, |
||
990 | 0, |
||
991 | value, |
||
992 | 0, |
||
993 | 0, |
||
994 | 1, |
||
995 | 0, |
||
996 | value, |
||
997 | 0, |
||
998 | 0, |
||
999 | 0, |
||
1000 | 1, |
||
1001 | 0, |
||
1002 | 0, |
||
1003 | 0, |
||
1004 | 0, |
||
1005 | 0, |
||
1006 | 1 |
||
1007 | ]); |
||
1008 | } |
||
1009 | function adjustColors(matrix, adjustR, adjustG, adjustB) { |
||
1010 | adjustR = clamp(adjustR, 0, 2); |
||
1011 | adjustG = clamp(adjustG, 0, 2); |
||
1012 | adjustB = clamp(adjustB, 0, 2); |
||
1013 | return multiply(matrix, [ |
||
1014 | adjustR, |
||
1015 | 0, |
||
1016 | 0, |
||
1017 | 0, |
||
1018 | 0, |
||
1019 | 0, |
||
1020 | adjustG, |
||
1021 | 0, |
||
1022 | 0, |
||
1023 | 0, |
||
1024 | 0, |
||
1025 | 0, |
||
1026 | adjustB, |
||
1027 | 0, |
||
1028 | 0, |
||
1029 | 0, |
||
1030 | 0, |
||
1031 | 0, |
||
1032 | 1, |
||
1033 | 0, |
||
1034 | 0, |
||
1035 | 0, |
||
1036 | 0, |
||
1037 | 0, |
||
1038 | 1 |
||
1039 | ]); |
||
1040 | } |
||
1041 | function adjustSepia(matrix, value) { |
||
1042 | value = clamp(value, 0, 1); |
||
1043 | return multiply(matrix, adjust([ |
||
1044 | 0.393, |
||
1045 | 0.769, |
||
1046 | 0.189, |
||
1047 | 0, |
||
1048 | 0, |
||
1049 | 0.349, |
||
1050 | 0.686, |
||
1051 | 0.168, |
||
1052 | 0, |
||
1053 | 0, |
||
1054 | 0.272, |
||
1055 | 0.534, |
||
1056 | 0.131, |
||
1057 | 0, |
||
1058 | 0, |
||
1059 | 0, |
||
1060 | 0, |
||
1061 | 0, |
||
1062 | 1, |
||
1063 | 0, |
||
1064 | 0, |
||
1065 | 0, |
||
1066 | 0, |
||
1067 | 0, |
||
1068 | 1 |
||
1069 | ], value)); |
||
1070 | } |
||
1071 | function adjustGrayscale(matrix, value) { |
||
1072 | value = clamp(value, 0, 1); |
||
1073 | return multiply(matrix, adjust([ |
||
1074 | 0.33, |
||
1075 | 0.34, |
||
1076 | 0.33, |
||
1077 | 0, |
||
1078 | 0, |
||
1079 | 0.33, |
||
1080 | 0.34, |
||
1081 | 0.33, |
||
1082 | 0, |
||
1083 | 0, |
||
1084 | 0.33, |
||
1085 | 0.34, |
||
1086 | 0.33, |
||
1087 | 0, |
||
1088 | 0, |
||
1089 | 0, |
||
1090 | 0, |
||
1091 | 0, |
||
1092 | 1, |
||
1093 | 0, |
||
1094 | 0, |
||
1095 | 0, |
||
1096 | 0, |
||
1097 | 0, |
||
1098 | 1 |
||
1099 | ], value)); |
||
1100 | } |
||
1101 | var ColorMatrix = { |
||
1102 | identity: identity$1, |
||
1103 | adjust: adjust, |
||
1104 | multiply: multiply, |
||
1105 | adjustContrast: adjustContrast, |
||
1106 | adjustBrightness: adjustBrightness, |
||
1107 | adjustSaturation: adjustSaturation, |
||
1108 | adjustHue: adjustHue, |
||
1109 | adjustColors: adjustColors, |
||
1110 | adjustSepia: adjustSepia, |
||
1111 | adjustGrayscale: adjustGrayscale |
||
1112 | }; |
||
1113 | |||
1114 | function colorFilter(ir, matrix) { |
||
1115 | return ir.toCanvas().then(function (canvas) { |
||
1116 | return applyColorFilter(canvas, ir.getType(), matrix); |
||
1117 | }); |
||
1118 | } |
||
1119 | function applyColorFilter(canvas, type, matrix) { |
||
1120 | var context = Canvas.get2dContext(canvas); |
||
1121 | var pixels; |
||
1122 | function applyMatrix(pixels, m) { |
||
1123 | var d = pixels.data, r, g, b, a, i, m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3], m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7], m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11], m12 = m[12], m13 = m[13], m14 = m[14], m15 = m[15], m16 = m[16], m17 = m[17], m18 = m[18], m19 = m[19]; |
||
1124 | for (i = 0; i < d.length; i += 4) { |
||
1125 | r = d[i]; |
||
1126 | g = d[i + 1]; |
||
1127 | b = d[i + 2]; |
||
1128 | a = d[i + 3]; |
||
1129 | d[i] = r * m0 + g * m1 + b * m2 + a * m3 + m4; |
||
1130 | d[i + 1] = r * m5 + g * m6 + b * m7 + a * m8 + m9; |
||
1131 | d[i + 2] = r * m10 + g * m11 + b * m12 + a * m13 + m14; |
||
1132 | d[i + 3] = r * m15 + g * m16 + b * m17 + a * m18 + m19; |
||
1133 | } |
||
1134 | return pixels; |
||
1135 | } |
||
1136 | pixels = applyMatrix(context.getImageData(0, 0, canvas.width, canvas.height), matrix); |
||
1137 | context.putImageData(pixels, 0, 0); |
||
1138 | return ImageResult.fromCanvas(canvas, type); |
||
1139 | } |
||
1140 | function convoluteFilter(ir, matrix) { |
||
1141 | return ir.toCanvas().then(function (canvas) { |
||
1142 | return applyConvoluteFilter(canvas, ir.getType(), matrix); |
||
1143 | }); |
||
1144 | } |
||
1145 | function applyConvoluteFilter(canvas, type, matrix) { |
||
1146 | var context = Canvas.get2dContext(canvas); |
||
1147 | var pixelsIn, pixelsOut; |
||
1148 | function applyMatrix(pixelsIn, pixelsOut, matrix) { |
||
1149 | var rgba, drgba, side, halfSide, x, y, r, g, b, cx, cy, scx, scy, offset, wt, w, h; |
||
1150 | function clamp(value, min, max) { |
||
1151 | if (value > max) { |
||
1152 | value = max; |
||
1153 | } else if (value < min) { |
||
1154 | value = min; |
||
1155 | } |
||
1156 | return value; |
||
1157 | } |
||
1158 | side = Math.round(Math.sqrt(matrix.length)); |
||
1159 | halfSide = Math.floor(side / 2); |
||
1160 | rgba = pixelsIn.data; |
||
1161 | drgba = pixelsOut.data; |
||
1162 | w = pixelsIn.width; |
||
1163 | h = pixelsIn.height; |
||
1164 | for (y = 0; y < h; y++) { |
||
1165 | for (x = 0; x < w; x++) { |
||
1166 | r = g = b = 0; |
||
1167 | for (cy = 0; cy < side; cy++) { |
||
1168 | for (cx = 0; cx < side; cx++) { |
||
1169 | scx = clamp(x + cx - halfSide, 0, w - 1); |
||
1170 | scy = clamp(y + cy - halfSide, 0, h - 1); |
||
1171 | offset = (scy * w + scx) * 4; |
||
1172 | wt = matrix[cy * side + cx]; |
||
1173 | r += rgba[offset] * wt; |
||
1174 | g += rgba[offset + 1] * wt; |
||
1175 | b += rgba[offset + 2] * wt; |
||
1176 | } |
||
1177 | } |
||
1178 | offset = (y * w + x) * 4; |
||
1179 | drgba[offset] = clamp(r, 0, 255); |
||
1180 | drgba[offset + 1] = clamp(g, 0, 255); |
||
1181 | drgba[offset + 2] = clamp(b, 0, 255); |
||
1182 | } |
||
1183 | } |
||
1184 | return pixelsOut; |
||
1185 | } |
||
1186 | pixelsIn = context.getImageData(0, 0, canvas.width, canvas.height); |
||
1187 | pixelsOut = context.getImageData(0, 0, canvas.width, canvas.height); |
||
1188 | pixelsOut = applyMatrix(pixelsIn, pixelsOut, matrix); |
||
1189 | context.putImageData(pixelsOut, 0, 0); |
||
1190 | return ImageResult.fromCanvas(canvas, type); |
||
1191 | } |
||
1192 | function functionColorFilter(colorFn) { |
||
1193 | var filterImpl = function (canvas, type, value) { |
||
1194 | var context = Canvas.get2dContext(canvas); |
||
1195 | var pixels, i, lookup = new Array(256); |
||
1196 | function applyLookup(pixels, lookup) { |
||
1197 | var d = pixels.data, i; |
||
1198 | for (i = 0; i < d.length; i += 4) { |
||
1199 | d[i] = lookup[d[i]]; |
||
1200 | d[i + 1] = lookup[d[i + 1]]; |
||
1201 | d[i + 2] = lookup[d[i + 2]]; |
||
1202 | } |
||
1203 | return pixels; |
||
1204 | } |
||
1205 | for (i = 0; i < lookup.length; i++) { |
||
1206 | lookup[i] = colorFn(i, value); |
||
1207 | } |
||
1208 | pixels = applyLookup(context.getImageData(0, 0, canvas.width, canvas.height), lookup); |
||
1209 | context.putImageData(pixels, 0, 0); |
||
1210 | return ImageResult.fromCanvas(canvas, type); |
||
1211 | }; |
||
1212 | return function (ir, value) { |
||
1213 | return ir.toCanvas().then(function (canvas) { |
||
1214 | return filterImpl(canvas, ir.getType(), value); |
||
1215 | }); |
||
1216 | }; |
||
1217 | } |
||
1218 | function complexAdjustableColorFilter(matrixAdjustFn) { |
||
1219 | return function (ir, adjust) { |
||
1220 | return colorFilter(ir, matrixAdjustFn(ColorMatrix.identity(), adjust)); |
||
1221 | }; |
||
1222 | } |
||
1223 | function basicColorFilter(matrix) { |
||
1224 | return function (ir) { |
||
1225 | return colorFilter(ir, matrix); |
||
1226 | }; |
||
1227 | } |
||
1228 | function basicConvolutionFilter(kernel) { |
||
1229 | return function (ir) { |
||
1230 | return convoluteFilter(ir, kernel); |
||
1231 | }; |
||
1232 | } |
||
1233 | var Filters = { |
||
1234 | invert: basicColorFilter([ |
||
1235 | -1, |
||
1236 | 0, |
||
1237 | 0, |
||
1238 | 0, |
||
1239 | 255, |
||
1240 | 0, |
||
1241 | -1, |
||
1242 | 0, |
||
1243 | 0, |
||
1244 | 255, |
||
1245 | 0, |
||
1246 | 0, |
||
1247 | -1, |
||
1248 | 0, |
||
1249 | 255, |
||
1250 | 0, |
||
1251 | 0, |
||
1252 | 0, |
||
1253 | 1, |
||
1254 | 0 |
||
1255 | ]), |
||
1256 | brightness: complexAdjustableColorFilter(ColorMatrix.adjustBrightness), |
||
1257 | hue: complexAdjustableColorFilter(ColorMatrix.adjustHue), |
||
1258 | saturate: complexAdjustableColorFilter(ColorMatrix.adjustSaturation), |
||
1259 | contrast: complexAdjustableColorFilter(ColorMatrix.adjustContrast), |
||
1260 | grayscale: complexAdjustableColorFilter(ColorMatrix.adjustGrayscale), |
||
1261 | sepia: complexAdjustableColorFilter(ColorMatrix.adjustSepia), |
||
1262 | colorize: function (ir, adjustR, adjustG, adjustB) { |
||
1263 | return colorFilter(ir, ColorMatrix.adjustColors(ColorMatrix.identity(), adjustR, adjustG, adjustB)); |
||
1264 | }, |
||
1265 | sharpen: basicConvolutionFilter([ |
||
1266 | 0, |
||
1267 | -1, |
||
1268 | 0, |
||
1269 | -1, |
||
1270 | 5, |
||
1271 | -1, |
||
1272 | 0, |
||
1273 | -1, |
||
1274 | 0 |
||
1275 | ]), |
||
1276 | emboss: basicConvolutionFilter([ |
||
1277 | -2, |
||
1278 | -1, |
||
1279 | 0, |
||
1280 | -1, |
||
1281 | 1, |
||
1282 | 1, |
||
1283 | 0, |
||
1284 | 1, |
||
1285 | 2 |
||
1286 | ]), |
||
1287 | gamma: functionColorFilter(function (color, value) { |
||
1288 | return Math.pow(color / 255, 1 - value) * 255; |
||
1289 | }), |
||
1290 | exposure: functionColorFilter(function (color, value) { |
||
1291 | return 255 * (1 - Math.exp(-(color / 255) * value)); |
||
1292 | }), |
||
1293 | colorFilter: colorFilter, |
||
1294 | convoluteFilter: convoluteFilter |
||
1295 | }; |
||
1296 | |||
1297 | function scale(image, dW, dH) { |
||
1298 | var sW = ImageSize.getWidth(image); |
||
1299 | var sH = ImageSize.getHeight(image); |
||
1300 | var wRatio = dW / sW; |
||
1301 | var hRatio = dH / sH; |
||
1302 | var scaleCapped = false; |
||
1303 | if (wRatio < 0.5 || wRatio > 2) { |
||
1304 | wRatio = wRatio < 0.5 ? 0.5 : 2; |
||
1305 | scaleCapped = true; |
||
1306 | } |
||
1307 | if (hRatio < 0.5 || hRatio > 2) { |
||
1308 | hRatio = hRatio < 0.5 ? 0.5 : 2; |
||
1309 | scaleCapped = true; |
||
1310 | } |
||
1311 | var scaled = _scale(image, wRatio, hRatio); |
||
1312 | return !scaleCapped ? scaled : scaled.then(function (tCanvas) { |
||
1313 | return scale(tCanvas, dW, dH); |
||
1314 | }); |
||
1315 | } |
||
1316 | function _scale(image, wRatio, hRatio) { |
||
1317 | return new Promise(function (resolve) { |
||
1318 | var sW = ImageSize.getWidth(image); |
||
1319 | var sH = ImageSize.getHeight(image); |
||
1320 | var dW = Math.floor(sW * wRatio); |
||
1321 | var dH = Math.floor(sH * hRatio); |
||
1322 | var canvas = Canvas.create(dW, dH); |
||
1323 | var context = Canvas.get2dContext(canvas); |
||
1324 | context.drawImage(image, 0, 0, sW, sH, 0, 0, dW, dH); |
||
1325 | resolve(canvas); |
||
1326 | }); |
||
1327 | } |
||
1328 | var ImageResizerCanvas = { scale: scale }; |
||
1329 | |||
1330 | function rotate(ir, angle) { |
||
1331 | return ir.toCanvas().then(function (canvas) { |
||
1332 | return applyRotate(canvas, ir.getType(), angle); |
||
1333 | }); |
||
1334 | } |
||
1335 | function applyRotate(image, type, angle) { |
||
1336 | var canvas = Canvas.create(image.width, image.height); |
||
1337 | var context = Canvas.get2dContext(canvas); |
||
1338 | var translateX = 0, translateY = 0; |
||
1339 | angle = angle < 0 ? 360 + angle : angle; |
||
1340 | if (angle == 90 || angle == 270) { |
||
1341 | Canvas.resize(canvas, canvas.height, canvas.width); |
||
1342 | } |
||
1343 | if (angle == 90 || angle == 180) { |
||
1344 | translateX = canvas.width; |
||
1345 | } |
||
1346 | if (angle == 270 || angle == 180) { |
||
1347 | translateY = canvas.height; |
||
1348 | } |
||
1349 | context.translate(translateX, translateY); |
||
1350 | context.rotate(angle * Math.PI / 180); |
||
1351 | context.drawImage(image, 0, 0); |
||
1352 | return ImageResult.fromCanvas(canvas, type); |
||
1353 | } |
||
1354 | function flip(ir, axis) { |
||
1355 | return ir.toCanvas().then(function (canvas) { |
||
1356 | return applyFlip(canvas, ir.getType(), axis); |
||
1357 | }); |
||
1358 | } |
||
1359 | function applyFlip(image, type, axis) { |
||
1360 | var canvas = Canvas.create(image.width, image.height); |
||
1361 | var context = Canvas.get2dContext(canvas); |
||
1362 | if (axis == 'v') { |
||
1363 | context.scale(1, -1); |
||
1364 | context.drawImage(image, 0, -canvas.height); |
||
1365 | } else { |
||
1366 | context.scale(-1, 1); |
||
1367 | context.drawImage(image, -canvas.width, 0); |
||
1368 | } |
||
1369 | return ImageResult.fromCanvas(canvas, type); |
||
1370 | } |
||
1371 | function crop(ir, x, y, w, h) { |
||
1372 | return ir.toCanvas().then(function (canvas) { |
||
1373 | return applyCrop(canvas, ir.getType(), x, y, w, h); |
||
1374 | }); |
||
1375 | } |
||
1376 | function applyCrop(image, type, x, y, w, h) { |
||
1377 | var canvas = Canvas.create(w, h); |
||
1378 | var context = Canvas.get2dContext(canvas); |
||
1379 | context.drawImage(image, -x, -y); |
||
1380 | return ImageResult.fromCanvas(canvas, type); |
||
1381 | } |
||
1382 | function resize$1(ir, w, h) { |
||
1383 | return ir.toCanvas().then(function (canvas) { |
||
1384 | return ImageResizerCanvas.scale(canvas, w, h).then(function (newCanvas) { |
||
1385 | return ImageResult.fromCanvas(newCanvas, ir.getType()); |
||
1386 | }); |
||
1387 | }); |
||
1388 | } |
||
1389 | var ImageTools = { |
||
1390 | rotate: rotate, |
||
1391 | flip: flip, |
||
1392 | crop: crop, |
||
1393 | resize: resize$1 |
||
1394 | }; |
||
1395 | |||
1396 | var BinaryReader = function () { |
||
1397 | function BinaryReader(ar) { |
||
1398 | this.littleEndian = false; |
||
1399 | this._dv = new DataView(ar); |
||
1400 | } |
||
1401 | BinaryReader.prototype.readByteAt = function (idx) { |
||
1402 | return this._dv.getUint8(idx); |
||
1403 | }; |
||
1404 | BinaryReader.prototype.read = function (idx, size) { |
||
1405 | if (idx + size > this.length()) { |
||
1406 | return null; |
||
1407 | } |
||
1408 | var mv = this.littleEndian ? 0 : -8 * (size - 1); |
||
1409 | for (var i = 0, sum = 0; i < size; i++) { |
||
1410 | sum |= this.readByteAt(idx + i) << Math.abs(mv + i * 8); |
||
1411 | } |
||
1412 | return sum; |
||
1413 | }; |
||
1414 | BinaryReader.prototype.BYTE = function (idx) { |
||
1415 | return this.read(idx, 1); |
||
1416 | }; |
||
1417 | BinaryReader.prototype.SHORT = function (idx) { |
||
1418 | return this.read(idx, 2); |
||
1419 | }; |
||
1420 | BinaryReader.prototype.LONG = function (idx) { |
||
1421 | return this.read(idx, 4); |
||
1422 | }; |
||
1423 | BinaryReader.prototype.SLONG = function (idx) { |
||
1424 | var num = this.read(idx, 4); |
||
1425 | return num > 2147483647 ? num - 4294967296 : num; |
||
1426 | }; |
||
1427 | BinaryReader.prototype.CHAR = function (idx) { |
||
1428 | return String.fromCharCode(this.read(idx, 1)); |
||
1429 | }; |
||
1430 | BinaryReader.prototype.STRING = function (idx, count) { |
||
1431 | return this.asArray('CHAR', idx, count).join(''); |
||
1432 | }; |
||
1433 | BinaryReader.prototype.SEGMENT = function (idx, size) { |
||
1434 | var ar = this._dv.buffer; |
||
1435 | switch (arguments.length) { |
||
1436 | case 2: |
||
1437 | return ar.slice(idx, idx + size); |
||
1438 | case 1: |
||
1439 | return ar.slice(idx); |
||
1440 | default: |
||
1441 | return ar; |
||
1442 | } |
||
1443 | }; |
||
1444 | BinaryReader.prototype.asArray = function (type, idx, count) { |
||
1445 | var values = []; |
||
1446 | for (var i = 0; i < count; i++) { |
||
1447 | values[i] = this[type](idx + i); |
||
1448 | } |
||
1449 | return values; |
||
1450 | }; |
||
1451 | BinaryReader.prototype.length = function () { |
||
1452 | return this._dv ? this._dv.byteLength : 0; |
||
1453 | }; |
||
1454 | return BinaryReader; |
||
1455 | }(); |
||
1456 | |||
1457 | var tags = { |
||
1458 | tiff: { |
||
1459 | 274: 'Orientation', |
||
1460 | 270: 'ImageDescription', |
||
1461 | 271: 'Make', |
||
1462 | 272: 'Model', |
||
1463 | 305: 'Software', |
||
1464 | 34665: 'ExifIFDPointer', |
||
1465 | 34853: 'GPSInfoIFDPointer' |
||
1466 | }, |
||
1467 | exif: { |
||
1468 | 36864: 'ExifVersion', |
||
1469 | 40961: 'ColorSpace', |
||
1470 | 40962: 'PixelXDimension', |
||
1471 | 40963: 'PixelYDimension', |
||
1472 | 36867: 'DateTimeOriginal', |
||
1473 | 33434: 'ExposureTime', |
||
1474 | 33437: 'FNumber', |
||
1475 | 34855: 'ISOSpeedRatings', |
||
1476 | 37377: 'ShutterSpeedValue', |
||
1477 | 37378: 'ApertureValue', |
||
1478 | 37383: 'MeteringMode', |
||
1479 | 37384: 'LightSource', |
||
1480 | 37385: 'Flash', |
||
1481 | 37386: 'FocalLength', |
||
1482 | 41986: 'ExposureMode', |
||
1483 | 41987: 'WhiteBalance', |
||
1484 | 41990: 'SceneCaptureType', |
||
1485 | 41988: 'DigitalZoomRatio', |
||
1486 | 41992: 'Contrast', |
||
1487 | 41993: 'Saturation', |
||
1488 | 41994: 'Sharpness' |
||
1489 | }, |
||
1490 | gps: { |
||
1491 | 0: 'GPSVersionID', |
||
1492 | 1: 'GPSLatitudeRef', |
||
1493 | 2: 'GPSLatitude', |
||
1494 | 3: 'GPSLongitudeRef', |
||
1495 | 4: 'GPSLongitude' |
||
1496 | }, |
||
1497 | thumb: { |
||
1498 | 513: 'JPEGInterchangeFormat', |
||
1499 | 514: 'JPEGInterchangeFormatLength' |
||
1500 | } |
||
1501 | }; |
||
1502 | var tagDescs = { |
||
1503 | 'ColorSpace': { |
||
1504 | 1: 'sRGB', |
||
1505 | 0: 'Uncalibrated' |
||
1506 | }, |
||
1507 | 'MeteringMode': { |
||
1508 | 0: 'Unknown', |
||
1509 | 1: 'Average', |
||
1510 | 2: 'CenterWeightedAverage', |
||
1511 | 3: 'Spot', |
||
1512 | 4: 'MultiSpot', |
||
1513 | 5: 'Pattern', |
||
1514 | 6: 'Partial', |
||
1515 | 255: 'Other' |
||
1516 | }, |
||
1517 | 'LightSource': { |
||
1518 | 1: 'Daylight', |
||
1519 | 2: 'Fliorescent', |
||
1520 | 3: 'Tungsten', |
||
1521 | 4: 'Flash', |
||
1522 | 9: 'Fine weather', |
||
1523 | 10: 'Cloudy weather', |
||
1524 | 11: 'Shade', |
||
1525 | 12: 'Daylight fluorescent (D 5700 - 7100K)', |
||
1526 | 13: 'Day white fluorescent (N 4600 -5400K)', |
||
1527 | 14: 'Cool white fluorescent (W 3900 - 4500K)', |
||
1528 | 15: 'White fluorescent (WW 3200 - 3700K)', |
||
1529 | 17: 'Standard light A', |
||
1530 | 18: 'Standard light B', |
||
1531 | 19: 'Standard light C', |
||
1532 | 20: 'D55', |
||
1533 | 21: 'D65', |
||
1534 | 22: 'D75', |
||
1535 | 23: 'D50', |
||
1536 | 24: 'ISO studio tungsten', |
||
1537 | 255: 'Other' |
||
1538 | }, |
||
1539 | 'Flash': { |
||
1540 | 0: 'Flash did not fire', |
||
1541 | 1: 'Flash fired', |
||
1542 | 5: 'Strobe return light not detected', |
||
1543 | 7: 'Strobe return light detected', |
||
1544 | 9: 'Flash fired, compulsory flash mode', |
||
1545 | 13: 'Flash fired, compulsory flash mode, return light not detected', |
||
1546 | 15: 'Flash fired, compulsory flash mode, return light detected', |
||
1547 | 16: 'Flash did not fire, compulsory flash mode', |
||
1548 | 24: 'Flash did not fire, auto mode', |
||
1549 | 25: 'Flash fired, auto mode', |
||
1550 | 29: 'Flash fired, auto mode, return light not detected', |
||
1551 | 31: 'Flash fired, auto mode, return light detected', |
||
1552 | 32: 'No flash function', |
||
1553 | 65: 'Flash fired, red-eye reduction mode', |
||
1554 | 69: 'Flash fired, red-eye reduction mode, return light not detected', |
||
1555 | 71: 'Flash fired, red-eye reduction mode, return light detected', |
||
1556 | 73: 'Flash fired, compulsory flash mode, red-eye reduction mode', |
||
1557 | 77: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected', |
||
1558 | 79: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected', |
||
1559 | 89: 'Flash fired, auto mode, red-eye reduction mode', |
||
1560 | 93: 'Flash fired, auto mode, return light not detected, red-eye reduction mode', |
||
1561 | 95: 'Flash fired, auto mode, return light detected, red-eye reduction mode' |
||
1562 | }, |
||
1563 | 'ExposureMode': { |
||
1564 | 0: 'Auto exposure', |
||
1565 | 1: 'Manual exposure', |
||
1566 | 2: 'Auto bracket' |
||
1567 | }, |
||
1568 | 'WhiteBalance': { |
||
1569 | 0: 'Auto white balance', |
||
1570 | 1: 'Manual white balance' |
||
1571 | }, |
||
1572 | 'SceneCaptureType': { |
||
1573 | 0: 'Standard', |
||
1574 | 1: 'Landscape', |
||
1575 | 2: 'Portrait', |
||
1576 | 3: 'Night scene' |
||
1577 | }, |
||
1578 | 'Contrast': { |
||
1579 | 0: 'Normal', |
||
1580 | 1: 'Soft', |
||
1581 | 2: 'Hard' |
||
1582 | }, |
||
1583 | 'Saturation': { |
||
1584 | 0: 'Normal', |
||
1585 | 1: 'Low saturation', |
||
1586 | 2: 'High saturation' |
||
1587 | }, |
||
1588 | 'Sharpness': { |
||
1589 | 0: 'Normal', |
||
1590 | 1: 'Soft', |
||
1591 | 2: 'Hard' |
||
1592 | }, |
||
1593 | 'GPSLatitudeRef': { |
||
1594 | N: 'North latitude', |
||
1595 | S: 'South latitude' |
||
1596 | }, |
||
1597 | 'GPSLongitudeRef': { |
||
1598 | E: 'East longitude', |
||
1599 | W: 'West longitude' |
||
1600 | } |
||
1601 | }; |
||
1602 | var ExifReader = function () { |
||
1603 | function ExifReader(ar) { |
||
1604 | this._offsets = { |
||
1605 | tiffHeader: 10, |
||
1606 | IFD0: null, |
||
1607 | IFD1: null, |
||
1608 | exifIFD: null, |
||
1609 | gpsIFD: null |
||
1610 | }; |
||
1611 | this._tiffTags = {}; |
||
1612 | var self = this; |
||
1613 | self._reader = new BinaryReader(ar); |
||
1614 | self._idx = self._offsets.tiffHeader; |
||
1615 | if (self.SHORT(0) !== 65505 || self.STRING(4, 5).toUpperCase() !== 'EXIF\0') { |
||
1616 | throw new Error('Exif data cannot be read or not available.'); |
||
1617 | } |
||
1618 | self._reader.littleEndian = self.SHORT(self._idx) == 18761; |
||
1619 | if (self.SHORT(self._idx += 2) !== 42) { |
||
1620 | throw new Error('Invalid Exif data.'); |
||
1621 | } |
||
1622 | self._offsets.IFD0 = self._offsets.tiffHeader + self.LONG(self._idx += 2); |
||
1623 | self._tiffTags = self.extractTags(self._offsets.IFD0, tags.tiff); |
||
1624 | if ('ExifIFDPointer' in self._tiffTags) { |
||
1625 | self._offsets.exifIFD = self._offsets.tiffHeader + self._tiffTags.ExifIFDPointer; |
||
1626 | delete self._tiffTags.ExifIFDPointer; |
||
1627 | } |
||
1628 | if ('GPSInfoIFDPointer' in self._tiffTags) { |
||
1629 | self._offsets.gpsIFD = self._offsets.tiffHeader + self._tiffTags.GPSInfoIFDPointer; |
||
1630 | delete self._tiffTags.GPSInfoIFDPointer; |
||
1631 | } |
||
1632 | var IFD1Offset = self.LONG(self._offsets.IFD0 + self.SHORT(self._offsets.IFD0) * 12 + 2); |
||
1633 | if (IFD1Offset) { |
||
1634 | self._offsets.IFD1 = self._offsets.tiffHeader + IFD1Offset; |
||
1635 | } |
||
1636 | } |
||
1637 | ExifReader.prototype.BYTE = function (idx) { |
||
1638 | return this._reader.BYTE(idx); |
||
1639 | }; |
||
1640 | ExifReader.prototype.SHORT = function (idx) { |
||
1641 | return this._reader.SHORT(idx); |
||
1642 | }; |
||
1643 | ExifReader.prototype.LONG = function (idx) { |
||
1644 | return this._reader.LONG(idx); |
||
1645 | }; |
||
1646 | ExifReader.prototype.SLONG = function (idx) { |
||
1647 | return this._reader.SLONG(idx); |
||
1648 | }; |
||
1649 | ExifReader.prototype.CHAR = function (idx) { |
||
1650 | return this._reader.CHAR(idx); |
||
1651 | }; |
||
1652 | ExifReader.prototype.STRING = function (idx, count) { |
||
1653 | return this._reader.STRING(idx, count); |
||
1654 | }; |
||
1655 | ExifReader.prototype.SEGMENT = function (idx, size) { |
||
1656 | return this._reader.SEGMENT(idx, size); |
||
1657 | }; |
||
1658 | ExifReader.prototype.asArray = function (type, idx, count) { |
||
1659 | var values = []; |
||
1660 | for (var i = 0; i < count; i++) { |
||
1661 | values[i] = this[type](idx + i); |
||
1662 | } |
||
1663 | return values; |
||
1664 | }; |
||
1665 | ExifReader.prototype.length = function () { |
||
1666 | return this._reader.length(); |
||
1667 | }; |
||
1668 | ExifReader.prototype.UNDEFINED = function () { |
||
1669 | return this.BYTE.apply(this, arguments); |
||
1670 | }; |
||
1671 | ExifReader.prototype.RATIONAL = function (idx) { |
||
1672 | return this.LONG(idx) / this.LONG(idx + 4); |
||
1673 | }; |
||
1674 | ExifReader.prototype.SRATIONAL = function (idx) { |
||
1675 | return this.SLONG(idx) / this.SLONG(idx + 4); |
||
1676 | }; |
||
1677 | ExifReader.prototype.ASCII = function (idx) { |
||
1678 | return this.CHAR(idx); |
||
1679 | }; |
||
1680 | ExifReader.prototype.TIFF = function () { |
||
1681 | return this._tiffTags; |
||
1682 | }; |
||
1683 | ExifReader.prototype.EXIF = function () { |
||
1684 | var self = this; |
||
1685 | var Exif = null; |
||
1686 | if (self._offsets.exifIFD) { |
||
1687 | try { |
||
1688 | Exif = self.extractTags(self._offsets.exifIFD, tags.exif); |
||
1689 | } catch (ex) { |
||
1690 | return null; |
||
1691 | } |
||
1692 | if (Exif.ExifVersion && Array.isArray(Exif.ExifVersion)) { |
||
1693 | for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) { |
||
1694 | exifVersion += String.fromCharCode(Exif.ExifVersion[i]); |
||
1695 | } |
||
1696 | Exif.ExifVersion = exifVersion; |
||
1697 | } |
||
1698 | } |
||
1699 | return Exif; |
||
1700 | }; |
||
1701 | ExifReader.prototype.GPS = function () { |
||
1702 | var self = this; |
||
1703 | var GPS = null; |
||
1704 | if (self._offsets.gpsIFD) { |
||
1705 | try { |
||
1706 | GPS = self.extractTags(self._offsets.gpsIFD, tags.gps); |
||
1707 | } catch (ex) { |
||
1708 | return null; |
||
1709 | } |
||
1710 | if (GPS.GPSVersionID && Array.isArray(GPS.GPSVersionID)) { |
||
1711 | GPS.GPSVersionID = GPS.GPSVersionID.join('.'); |
||
1712 | } |
||
1713 | } |
||
1714 | return GPS; |
||
1715 | }; |
||
1716 | ExifReader.prototype.thumb = function () { |
||
1717 | var self = this; |
||
1718 | if (self._offsets.IFD1) { |
||
1719 | try { |
||
1720 | var IFD1Tags = self.extractTags(self._offsets.IFD1, tags.thumb); |
||
1721 | if ('JPEGInterchangeFormat' in IFD1Tags) { |
||
1722 | return self.SEGMENT(self._offsets.tiffHeader + IFD1Tags.JPEGInterchangeFormat, IFD1Tags.JPEGInterchangeFormatLength); |
||
1723 | } |
||
1724 | } catch (ex) { |
||
1725 | } |
||
1726 | } |
||
1727 | return null; |
||
1728 | }; |
||
1729 | ExifReader.prototype.extractTags = function (IFD_offset, tags2extract) { |
||
1730 | var self = this; |
||
1731 | var length, i, tag, type, count, size, offset, value, values = [], hash = {}; |
||
1732 | var types = { |
||
1733 | 1: 'BYTE', |
||
1734 | 7: 'UNDEFINED', |
||
1735 | 2: 'ASCII', |
||
1736 | 3: 'SHORT', |
||
1737 | 4: 'LONG', |
||
1738 | 5: 'RATIONAL', |
||
1739 | 9: 'SLONG', |
||
1740 | 10: 'SRATIONAL' |
||
1741 | }; |
||
1742 | var sizes = { |
||
1743 | 'BYTE': 1, |
||
1744 | 'UNDEFINED': 1, |
||
1745 | 'ASCII': 1, |
||
1746 | 'SHORT': 2, |
||
1747 | 'LONG': 4, |
||
1748 | 'RATIONAL': 8, |
||
1749 | 'SLONG': 4, |
||
1750 | 'SRATIONAL': 8 |
||
1751 | }; |
||
1752 | length = self.SHORT(IFD_offset); |
||
1753 | for (i = 0; i < length; i++) { |
||
1754 | values = []; |
||
1755 | offset = IFD_offset + 2 + i * 12; |
||
1756 | tag = tags2extract[self.SHORT(offset)]; |
||
1757 | if (tag === undefined) { |
||
1758 | continue; |
||
1759 | } |
||
1760 | type = types[self.SHORT(offset += 2)]; |
||
1761 | count = self.LONG(offset += 2); |
||
1762 | size = sizes[type]; |
||
1763 | if (!size) { |
||
1764 | throw new Error('Invalid Exif data.'); |
||
1765 | } |
||
1766 | offset += 4; |
||
1767 | if (size * count > 4) { |
||
1768 | offset = self.LONG(offset) + self._offsets.tiffHeader; |
||
1769 | } |
||
1770 | if (offset + size * count >= self.length()) { |
||
1771 | throw new Error('Invalid Exif data.'); |
||
1772 | } |
||
1773 | if (type === 'ASCII') { |
||
1774 | hash[tag] = self.STRING(offset, count).replace(/\0$/, '').trim(); |
||
1775 | continue; |
||
1776 | } else { |
||
1777 | values = self.asArray(type, offset, count); |
||
1778 | value = count == 1 ? values[0] : values; |
||
1779 | if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') { |
||
1780 | hash[tag] = tagDescs[tag][value]; |
||
1781 | } else { |
||
1782 | hash[tag] = value; |
||
1783 | } |
||
1784 | } |
||
1785 | } |
||
1786 | return hash; |
||
1787 | }; |
||
1788 | return ExifReader; |
||
1789 | }(); |
||
1790 | |||
1791 | var extractFrom = function (blob) { |
||
1792 | return Conversions.blobToArrayBuffer(blob).then(function (ar) { |
||
1793 | try { |
||
1794 | var br = new BinaryReader(ar); |
||
1795 | if (br.SHORT(0) === 65496) { |
||
1796 | var headers = extractHeaders(br); |
||
1797 | var app1 = headers.filter(function (header) { |
||
1798 | return header.name === 'APP1'; |
||
1799 | }); |
||
1800 | var meta = {}; |
||
1801 | if (app1.length) { |
||
1802 | var exifReader = new ExifReader(app1[0].segment); |
||
1803 | meta = { |
||
1804 | tiff: exifReader.TIFF(), |
||
1805 | exif: exifReader.EXIF(), |
||
1806 | gps: exifReader.GPS(), |
||
1807 | thumb: exifReader.thumb() |
||
1808 | }; |
||
1809 | } else { |
||
1810 | return Promise.reject('Headers did not include required information'); |
||
1811 | } |
||
1812 | meta.rawHeaders = headers; |
||
1813 | return meta; |
||
1814 | } |
||
1815 | return Promise.reject('Image was not a jpeg'); |
||
1816 | } catch (ex) { |
||
1817 | return Promise.reject('Unsupported format or not an image: ' + blob.type + ' (Exception: ' + ex.message + ')'); |
||
1818 | } |
||
1819 | }); |
||
1820 | }; |
||
1821 | var extractHeaders = function (br) { |
||
1822 | var headers = [], idx, marker, length = 0; |
||
1823 | idx = 2; |
||
1824 | while (idx <= br.length()) { |
||
1825 | marker = br.SHORT(idx); |
||
1826 | if (marker >= 65488 && marker <= 65495) { |
||
1827 | idx += 2; |
||
1828 | continue; |
||
1829 | } |
||
1830 | if (marker === 65498 || marker === 65497) { |
||
1831 | break; |
||
1832 | } |
||
1833 | length = br.SHORT(idx + 2) + 2; |
||
1834 | if (marker >= 65505 && marker <= 65519) { |
||
1835 | headers.push({ |
||
1836 | hex: marker, |
||
1837 | name: 'APP' + (marker & 15), |
||
1838 | start: idx, |
||
1839 | length: length, |
||
1840 | segment: br.SEGMENT(idx, length) |
||
1841 | }); |
||
1842 | } |
||
1843 | idx += length; |
||
1844 | } |
||
1845 | return headers; |
||
1846 | }; |
||
1847 | var JPEGMeta = { extractFrom: extractFrom }; |
||
1848 | |||
1849 | var invert = function (ir) { |
||
1850 | return Filters.invert(ir); |
||
1851 | }; |
||
1852 | var sharpen = function (ir) { |
||
1853 | return Filters.sharpen(ir); |
||
1854 | }; |
||
1855 | var emboss = function (ir) { |
||
1856 | return Filters.emboss(ir); |
||
1857 | }; |
||
1858 | var gamma = function (ir, value) { |
||
1859 | return Filters.gamma(ir, value); |
||
1860 | }; |
||
1861 | var exposure = function (ir, value) { |
||
1862 | return Filters.exposure(ir, value); |
||
1863 | }; |
||
1864 | var colorize = function (ir, adjustR, adjustG, adjustB) { |
||
1865 | return Filters.colorize(ir, adjustR, adjustG, adjustB); |
||
1866 | }; |
||
1867 | var brightness = function (ir, adjust) { |
||
1868 | return Filters.brightness(ir, adjust); |
||
1869 | }; |
||
1870 | var hue = function (ir, adjust) { |
||
1871 | return Filters.hue(ir, adjust); |
||
1872 | }; |
||
1873 | var saturate = function (ir, adjust) { |
||
1874 | return Filters.saturate(ir, adjust); |
||
1875 | }; |
||
1876 | var contrast = function (ir, adjust) { |
||
1877 | return Filters.contrast(ir, adjust); |
||
1878 | }; |
||
1879 | var grayscale = function (ir, adjust) { |
||
1880 | return Filters.grayscale(ir, adjust); |
||
1881 | }; |
||
1882 | var sepia = function (ir, adjust) { |
||
1883 | return Filters.sepia(ir, adjust); |
||
1884 | }; |
||
1885 | var flip$1 = function (ir, axis) { |
||
1886 | return ImageTools.flip(ir, axis); |
||
1887 | }; |
||
1888 | var crop$1 = function (ir, x, y, w, h) { |
||
1889 | return ImageTools.crop(ir, x, y, w, h); |
||
1890 | }; |
||
1891 | var resize$2 = function (ir, w, h) { |
||
1892 | return ImageTools.resize(ir, w, h); |
||
1893 | }; |
||
1894 | var rotate$1 = function (ir, angle) { |
||
1895 | return ImageTools.rotate(ir, angle); |
||
1896 | }; |
||
1897 | var exifRotate = function (ir) { |
||
1898 | var ROTATE_90 = 6; |
||
1899 | var ROTATE_180 = 3; |
||
1900 | var ROTATE_270 = 8; |
||
1901 | var checkRotation = function (data) { |
||
1902 | var orientation = data.tiff.Orientation; |
||
1903 | switch (orientation) { |
||
1904 | case ROTATE_90: |
||
1905 | return rotate$1(ir, 90); |
||
1906 | case ROTATE_180: |
||
1907 | return rotate$1(ir, 180); |
||
1908 | case ROTATE_270: |
||
1909 | return rotate$1(ir, 270); |
||
1910 | default: |
||
1911 | return ir; |
||
1912 | } |
||
1913 | }; |
||
1914 | var notJpeg = function () { |
||
1915 | return ir; |
||
1916 | }; |
||
1917 | return ir.toBlob().then(JPEGMeta.extractFrom).then(checkRotation, notJpeg); |
||
1918 | }; |
||
1919 | var ImageTransformations = { |
||
1920 | invert: invert, |
||
1921 | sharpen: sharpen, |
||
1922 | emboss: emboss, |
||
1923 | brightness: brightness, |
||
1924 | hue: hue, |
||
1925 | saturate: saturate, |
||
1926 | contrast: contrast, |
||
1927 | grayscale: grayscale, |
||
1928 | sepia: sepia, |
||
1929 | colorize: colorize, |
||
1930 | gamma: gamma, |
||
1931 | exposure: exposure, |
||
1932 | flip: flip$1, |
||
1933 | crop: crop$1, |
||
1934 | resize: resize$2, |
||
1935 | rotate: rotate$1, |
||
1936 | exifRotate: exifRotate |
||
1937 | }; |
||
1938 | |||
1939 | var blobToImageResult = function (blob) { |
||
1940 | return ImageResult.fromBlob(blob); |
||
1941 | }; |
||
1942 | var fromBlobAndUrlSync$1 = function (blob, uri) { |
||
1943 | return ImageResult.fromBlobAndUrlSync(blob, uri); |
||
1944 | }; |
||
1945 | var imageToImageResult = function (image) { |
||
1946 | return ImageResult.fromImage(image); |
||
1947 | }; |
||
1948 | var imageResultToBlob = function (ir, type, quality) { |
||
1949 | if (type === undefined && quality === undefined) { |
||
1950 | return imageResultToOriginalBlob(ir); |
||
1951 | } else { |
||
1952 | return ir.toAdjustedBlob(type, quality); |
||
1953 | } |
||
1954 | }; |
||
1955 | var imageResultToOriginalBlob = function (ir) { |
||
1956 | return ir.toBlob(); |
||
1957 | }; |
||
1958 | var imageResultToDataURL = function (ir) { |
||
1959 | return ir.toDataURL(); |
||
1960 | }; |
||
1961 | var ResultConversions = { |
||
1962 | blobToImageResult: blobToImageResult, |
||
1963 | fromBlobAndUrlSync: fromBlobAndUrlSync$1, |
||
1964 | imageToImageResult: imageToImageResult, |
||
1965 | imageResultToBlob: imageResultToBlob, |
||
1966 | imageResultToOriginalBlob: imageResultToOriginalBlob, |
||
1967 | imageResultToDataURL: imageResultToDataURL |
||
1968 | }; |
||
1969 | |||
1970 | var url = function () { |
||
1971 | return Global$1.getOrDie('URL'); |
||
1972 | }; |
||
1973 | var createObjectURL = function (blob) { |
||
1974 | return url().createObjectURL(blob); |
||
1975 | }; |
||
1976 | var revokeObjectURL = function (u) { |
||
1977 | url().revokeObjectURL(u); |
||
1978 | }; |
||
1979 | var URL$1 = { |
||
1980 | createObjectURL: createObjectURL, |
||
1981 | revokeObjectURL: revokeObjectURL |
||
1982 | }; |
||
1983 | |||
1984 | var global$2 = tinymce.util.Tools.resolve('tinymce.util.Delay'); |
||
1985 | |||
1986 | var global$3 = tinymce.util.Tools.resolve('tinymce.util.Promise'); |
||
1987 | |||
1988 | var global$4 = tinymce.util.Tools.resolve('tinymce.util.URI'); |
||
1989 | |||
1990 | var getToolbarItems = function (editor) { |
||
1991 | return editor.getParam('imagetools_toolbar', 'rotateleft rotateright | flipv fliph | crop editimage imageoptions'); |
||
1992 | }; |
||
1993 | var getProxyUrl = function (editor) { |
||
1994 | return editor.getParam('imagetools_proxy'); |
||
1995 | }; |
||
1996 | var getCorsHosts = function (editor) { |
||
1997 | return editor.getParam('imagetools_cors_hosts', [], 'string[]'); |
||
1998 | }; |
||
1999 | var getCredentialsHosts = function (editor) { |
||
2000 | return editor.getParam('imagetools_credentials_hosts', [], 'string[]'); |
||
2001 | }; |
||
2002 | var getApiKey = function (editor) { |
||
2003 | return editor.getParam('api_key', editor.getParam('imagetools_api_key', '', 'string'), 'string'); |
||
2004 | }; |
||
2005 | var getUploadTimeout = function (editor) { |
||
2006 | return editor.getParam('images_upload_timeout', 30000, 'number'); |
||
2007 | }; |
||
2008 | var shouldReuseFilename = function (editor) { |
||
2009 | return editor.getParam('images_reuse_filename', false, 'boolean'); |
||
2010 | }; |
||
2011 | |||
2012 | var global$5 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils'); |
||
2013 | |||
2014 | var global$6 = tinymce.util.Tools.resolve('tinymce.ui.Factory'); |
||
2015 | |||
2016 | function UndoStack () { |
||
2017 | var data = []; |
||
2018 | var index = -1; |
||
2019 | function add(state) { |
||
2020 | var removed; |
||
2021 | removed = data.splice(++index); |
||
2022 | data.push(state); |
||
2023 | return { |
||
2024 | state: state, |
||
2025 | removed: removed |
||
2026 | }; |
||
2027 | } |
||
2028 | function undo() { |
||
2029 | if (canUndo()) { |
||
2030 | return data[--index]; |
||
2031 | } |
||
2032 | } |
||
2033 | function redo() { |
||
2034 | if (canRedo()) { |
||
2035 | return data[++index]; |
||
2036 | } |
||
2037 | } |
||
2038 | function canUndo() { |
||
2039 | return index > 0; |
||
2040 | } |
||
2041 | function canRedo() { |
||
2042 | return index !== -1 && index < data.length - 1; |
||
2043 | } |
||
2044 | return { |
||
2045 | data: data, |
||
2046 | add: add, |
||
2047 | undo: undo, |
||
2048 | redo: redo, |
||
2049 | canUndo: canUndo, |
||
2050 | canRedo: canRedo |
||
2051 | }; |
||
2052 | } |
||
2053 | |||
2054 | var global$7 = tinymce.util.Tools.resolve('tinymce.geom.Rect'); |
||
2055 | |||
2056 | var loadImage$1 = function (image) { |
||
2057 | return new global$3(function (resolve) { |
||
2058 | var loaded = function () { |
||
2059 | image.removeEventListener('load', loaded); |
||
2060 | resolve(image); |
||
2061 | }; |
||
2062 | if (image.complete) { |
||
2063 | resolve(image); |
||
2064 | } else { |
||
2065 | image.addEventListener('load', loaded); |
||
2066 | } |
||
2067 | }); |
||
2068 | }; |
||
2069 | var LoadImage = { loadImage: loadImage$1 }; |
||
2070 | |||
2071 | var global$8 = tinymce.util.Tools.resolve('tinymce.dom.DomQuery'); |
||
2072 | |||
2073 | var global$9 = tinymce.util.Tools.resolve('tinymce.util.Observable'); |
||
2074 | |||
2075 | var global$a = tinymce.util.Tools.resolve('tinymce.util.VK'); |
||
2076 | |||
2077 | var count = 0; |
||
2078 | function CropRect (currentRect, viewPortRect, clampRect, containerElm, action) { |
||
2079 | var instance; |
||
2080 | var handles; |
||
2081 | var dragHelpers; |
||
2082 | var blockers; |
||
2083 | var prefix = 'mce-'; |
||
2084 | var id = prefix + 'crid-' + count++; |
||
2085 | handles = [ |
||
2086 | { |
||
2087 | name: 'move', |
||
2088 | xMul: 0, |
||
2089 | yMul: 0, |
||
2090 | deltaX: 1, |
||
2091 | deltaY: 1, |
||
2092 | deltaW: 0, |
||
2093 | deltaH: 0, |
||
2094 | label: 'Crop Mask' |
||
2095 | }, |
||
2096 | { |
||
2097 | name: 'nw', |
||
2098 | xMul: 0, |
||
2099 | yMul: 0, |
||
2100 | deltaX: 1, |
||
2101 | deltaY: 1, |
||
2102 | deltaW: -1, |
||
2103 | deltaH: -1, |
||
2104 | label: 'Top Left Crop Handle' |
||
2105 | }, |
||
2106 | { |
||
2107 | name: 'ne', |
||
2108 | xMul: 1, |
||
2109 | yMul: 0, |
||
2110 | deltaX: 0, |
||
2111 | deltaY: 1, |
||
2112 | deltaW: 1, |
||
2113 | deltaH: -1, |
||
2114 | label: 'Top Right Crop Handle' |
||
2115 | }, |
||
2116 | { |
||
2117 | name: 'sw', |
||
2118 | xMul: 0, |
||
2119 | yMul: 1, |
||
2120 | deltaX: 1, |
||
2121 | deltaY: 0, |
||
2122 | deltaW: -1, |
||
2123 | deltaH: 1, |
||
2124 | label: 'Bottom Left Crop Handle' |
||
2125 | }, |
||
2126 | { |
||
2127 | name: 'se', |
||
2128 | xMul: 1, |
||
2129 | yMul: 1, |
||
2130 | deltaX: 0, |
||
2131 | deltaY: 0, |
||
2132 | deltaW: 1, |
||
2133 | deltaH: 1, |
||
2134 | label: 'Bottom Right Crop Handle' |
||
2135 | } |
||
2136 | ]; |
||
2137 | blockers = [ |
||
2138 | 'top', |
||
2139 | 'right', |
||
2140 | 'bottom', |
||
2141 | 'left' |
||
2142 | ]; |
||
2143 | function getAbsoluteRect(outerRect, relativeRect) { |
||
2144 | return { |
||
2145 | x: relativeRect.x + outerRect.x, |
||
2146 | y: relativeRect.y + outerRect.y, |
||
2147 | w: relativeRect.w, |
||
2148 | h: relativeRect.h |
||
2149 | }; |
||
2150 | } |
||
2151 | function getRelativeRect(outerRect, innerRect) { |
||
2152 | return { |
||
2153 | x: innerRect.x - outerRect.x, |
||
2154 | y: innerRect.y - outerRect.y, |
||
2155 | w: innerRect.w, |
||
2156 | h: innerRect.h |
||
2157 | }; |
||
2158 | } |
||
2159 | function getInnerRect() { |
||
2160 | return getRelativeRect(clampRect, currentRect); |
||
2161 | } |
||
2162 | function moveRect(handle, startRect, deltaX, deltaY) { |
||
2163 | var x, y, w, h, rect; |
||
2164 | x = startRect.x; |
||
2165 | y = startRect.y; |
||
2166 | w = startRect.w; |
||
2167 | h = startRect.h; |
||
2168 | x += deltaX * handle.deltaX; |
||
2169 | y += deltaY * handle.deltaY; |
||
2170 | w += deltaX * handle.deltaW; |
||
2171 | h += deltaY * handle.deltaH; |
||
2172 | if (w < 20) { |
||
2173 | w = 20; |
||
2174 | } |
||
2175 | if (h < 20) { |
||
2176 | h = 20; |
||
2177 | } |
||
2178 | rect = currentRect = global$7.clamp({ |
||
2179 | x: x, |
||
2180 | y: y, |
||
2181 | w: w, |
||
2182 | h: h |
||
2183 | }, clampRect, handle.name === 'move'); |
||
2184 | rect = getRelativeRect(clampRect, rect); |
||
2185 | instance.fire('updateRect', { rect: rect }); |
||
2186 | setInnerRect(rect); |
||
2187 | } |
||
2188 | function render() { |
||
2189 | function createDragHelper(handle) { |
||
2190 | var startRect; |
||
2191 | var DragHelper = global$6.get('DragHelper'); |
||
2192 | return new DragHelper(id, { |
||
2193 | document: containerElm.ownerDocument, |
||
2194 | handle: id + '-' + handle.name, |
||
2195 | start: function () { |
||
2196 | startRect = currentRect; |
||
2197 | }, |
||
2198 | drag: function (e) { |
||
2199 | moveRect(handle, startRect, e.deltaX, e.deltaY); |
||
2200 | } |
||
2201 | }); |
||
2202 | } |
||
2203 | global$8('<div id="' + id + '" class="' + prefix + 'croprect-container"' + ' role="grid" aria-dropeffect="execute">').appendTo(containerElm); |
||
2204 | global$1.each(blockers, function (blocker) { |
||
2205 | global$8('#' + id, containerElm).append('<div id="' + id + '-' + blocker + '"class="' + prefix + 'croprect-block" style="display: none" data-mce-bogus="all">'); |
||
2206 | }); |
||
2207 | global$1.each(handles, function (handle) { |
||
2208 | global$8('#' + id, containerElm).append('<div id="' + id + '-' + handle.name + '" class="' + prefix + 'croprect-handle ' + prefix + 'croprect-handle-' + handle.name + '"' + 'style="display: none" data-mce-bogus="all" role="gridcell" tabindex="-1"' + ' aria-label="' + handle.label + '" aria-grabbed="false">'); |
||
2209 | }); |
||
2210 | dragHelpers = global$1.map(handles, createDragHelper); |
||
2211 | repaint(currentRect); |
||
2212 | global$8(containerElm).on('focusin focusout', function (e) { |
||
2213 | global$8(e.target).attr('aria-grabbed', e.type === 'focus'); |
||
2214 | }); |
||
2215 | global$8(containerElm).on('keydown', function (e) { |
||
2216 | var activeHandle; |
||
2217 | global$1.each(handles, function (handle) { |
||
2218 | if (e.target.id === id + '-' + handle.name) { |
||
2219 | activeHandle = handle; |
||
2220 | return false; |
||
2221 | } |
||
2222 | }); |
||
2223 | function moveAndBlock(evt, handle, startRect, deltaX, deltaY) { |
||
2224 | evt.stopPropagation(); |
||
2225 | evt.preventDefault(); |
||
2226 | moveRect(activeHandle, startRect, deltaX, deltaY); |
||
2227 | } |
||
2228 | switch (e.keyCode) { |
||
2229 | case global$a.LEFT: |
||
2230 | moveAndBlock(e, activeHandle, currentRect, -10, 0); |
||
2231 | break; |
||
2232 | case global$a.RIGHT: |
||
2233 | moveAndBlock(e, activeHandle, currentRect, 10, 0); |
||
2234 | break; |
||
2235 | case global$a.UP: |
||
2236 | moveAndBlock(e, activeHandle, currentRect, 0, -10); |
||
2237 | break; |
||
2238 | case global$a.DOWN: |
||
2239 | moveAndBlock(e, activeHandle, currentRect, 0, 10); |
||
2240 | break; |
||
2241 | case global$a.ENTER: |
||
2242 | case global$a.SPACEBAR: |
||
2243 | e.preventDefault(); |
||
2244 | action(); |
||
2245 | break; |
||
2246 | } |
||
2247 | }); |
||
2248 | } |
||
2249 | function toggleVisibility(state) { |
||
2250 | var selectors; |
||
2251 | selectors = global$1.map(handles, function (handle) { |
||
2252 | return '#' + id + '-' + handle.name; |
||
2253 | }).concat(global$1.map(blockers, function (blocker) { |
||
2254 | return '#' + id + '-' + blocker; |
||
2255 | })).join(','); |
||
2256 | if (state) { |
||
2257 | global$8(selectors, containerElm).show(); |
||
2258 | } else { |
||
2259 | global$8(selectors, containerElm).hide(); |
||
2260 | } |
||
2261 | } |
||
2262 | function repaint(rect) { |
||
2263 | function updateElementRect(name, rect) { |
||
2264 | if (rect.h < 0) { |
||
2265 | rect.h = 0; |
||
2266 | } |
||
2267 | if (rect.w < 0) { |
||
2268 | rect.w = 0; |
||
2269 | } |
||
2270 | global$8('#' + id + '-' + name, containerElm).css({ |
||
2271 | left: rect.x, |
||
2272 | top: rect.y, |
||
2273 | width: rect.w, |
||
2274 | height: rect.h |
||
2275 | }); |
||
2276 | } |
||
2277 | global$1.each(handles, function (handle) { |
||
2278 | global$8('#' + id + '-' + handle.name, containerElm).css({ |
||
2279 | left: rect.w * handle.xMul + rect.x, |
||
2280 | top: rect.h * handle.yMul + rect.y |
||
2281 | }); |
||
2282 | }); |
||
2283 | updateElementRect('top', { |
||
2284 | x: viewPortRect.x, |
||
2285 | y: viewPortRect.y, |
||
2286 | w: viewPortRect.w, |
||
2287 | h: rect.y - viewPortRect.y |
||
2288 | }); |
||
2289 | updateElementRect('right', { |
||
2290 | x: rect.x + rect.w, |
||
2291 | y: rect.y, |
||
2292 | w: viewPortRect.w - rect.x - rect.w + viewPortRect.x, |
||
2293 | h: rect.h |
||
2294 | }); |
||
2295 | updateElementRect('bottom', { |
||
2296 | x: viewPortRect.x, |
||
2297 | y: rect.y + rect.h, |
||
2298 | w: viewPortRect.w, |
||
2299 | h: viewPortRect.h - rect.y - rect.h + viewPortRect.y |
||
2300 | }); |
||
2301 | updateElementRect('left', { |
||
2302 | x: viewPortRect.x, |
||
2303 | y: rect.y, |
||
2304 | w: rect.x - viewPortRect.x, |
||
2305 | h: rect.h |
||
2306 | }); |
||
2307 | updateElementRect('move', rect); |
||
2308 | } |
||
2309 | function setRect(rect) { |
||
2310 | currentRect = rect; |
||
2311 | repaint(currentRect); |
||
2312 | } |
||
2313 | function setViewPortRect(rect) { |
||
2314 | viewPortRect = rect; |
||
2315 | repaint(currentRect); |
||
2316 | } |
||
2317 | function setInnerRect(rect) { |
||
2318 | setRect(getAbsoluteRect(clampRect, rect)); |
||
2319 | } |
||
2320 | function setClampRect(rect) { |
||
2321 | clampRect = rect; |
||
2322 | repaint(currentRect); |
||
2323 | } |
||
2324 | function destroy() { |
||
2325 | global$1.each(dragHelpers, function (helper) { |
||
2326 | helper.destroy(); |
||
2327 | }); |
||
2328 | dragHelpers = []; |
||
2329 | } |
||
2330 | render(); |
||
2331 | instance = global$1.extend({ |
||
2332 | toggleVisibility: toggleVisibility, |
||
2333 | setClampRect: setClampRect, |
||
2334 | setRect: setRect, |
||
2335 | getInnerRect: getInnerRect, |
||
2336 | setInnerRect: setInnerRect, |
||
2337 | setViewPortRect: setViewPortRect, |
||
2338 | destroy: destroy |
||
2339 | }, global$9); |
||
2340 | return instance; |
||
2341 | } |
||
2342 | |||
2343 | var create$2 = function (settings) { |
||
2344 | var Control = global$6.get('Control'); |
||
2345 | var ImagePanel = Control.extend({ |
||
2346 | Defaults: { classes: 'imagepanel' }, |
||
2347 | selection: function (rect) { |
||
2348 | if (arguments.length) { |
||
2349 | this.state.set('rect', rect); |
||
2350 | return this; |
||
2351 | } |
||
2352 | return this.state.get('rect'); |
||
2353 | }, |
||
2354 | imageSize: function () { |
||
2355 | var viewRect = this.state.get('viewRect'); |
||
2356 | return { |
||
2357 | w: viewRect.w, |
||
2358 | h: viewRect.h |
||
2359 | }; |
||
2360 | }, |
||
2361 | toggleCropRect: function (state) { |
||
2362 | this.state.set('cropEnabled', state); |
||
2363 | }, |
||
2364 | imageSrc: function (url) { |
||
2365 | var self$$1 = this, img = new Image(); |
||
2366 | img.src = url; |
||
2367 | LoadImage.loadImage(img).then(function () { |
||
2368 | var rect, $img; |
||
2369 | var lastRect = self$$1.state.get('viewRect'); |
||
2370 | $img = self$$1.$el.find('img'); |
||
2371 | if ($img[0]) { |
||
2372 | $img.replaceWith(img); |
||
2373 | } else { |
||
2374 | var bg = document.createElement('div'); |
||
2375 | bg.className = 'mce-imagepanel-bg'; |
||
2376 | self$$1.getEl().appendChild(bg); |
||
2377 | self$$1.getEl().appendChild(img); |
||
2378 | } |
||
2379 | rect = { |
||
2380 | x: 0, |
||
2381 | y: 0, |
||
2382 | w: img.naturalWidth, |
||
2383 | h: img.naturalHeight |
||
2384 | }; |
||
2385 | self$$1.state.set('viewRect', rect); |
||
2386 | self$$1.state.set('rect', global$7.inflate(rect, -20, -20)); |
||
2387 | if (!lastRect || lastRect.w !== rect.w || lastRect.h !== rect.h) { |
||
2388 | self$$1.zoomFit(); |
||
2389 | } |
||
2390 | self$$1.repaintImage(); |
||
2391 | self$$1.fire('load'); |
||
2392 | }); |
||
2393 | }, |
||
2394 | zoom: function (value) { |
||
2395 | if (arguments.length) { |
||
2396 | this.state.set('zoom', value); |
||
2397 | return this; |
||
2398 | } |
||
2399 | return this.state.get('zoom'); |
||
2400 | }, |
||
2401 | postRender: function () { |
||
2402 | this.imageSrc(this.settings.imageSrc); |
||
2403 | return this._super(); |
||
2404 | }, |
||
2405 | zoomFit: function () { |
||
2406 | var self$$1 = this; |
||
2407 | var $img, pw, ph, w, h, zoom, padding; |
||
2408 | padding = 10; |
||
2409 | $img = self$$1.$el.find('img'); |
||
2410 | pw = self$$1.getEl().clientWidth; |
||
2411 | ph = self$$1.getEl().clientHeight; |
||
2412 | w = $img[0].naturalWidth; |
||
2413 | h = $img[0].naturalHeight; |
||
2414 | zoom = Math.min((pw - padding) / w, (ph - padding) / h); |
||
2415 | if (zoom >= 1) { |
||
2416 | zoom = 1; |
||
2417 | } |
||
2418 | self$$1.zoom(zoom); |
||
2419 | }, |
||
2420 | repaintImage: function () { |
||
2421 | var x, y, w, h, pw, ph, $img, $bg, zoom, rect, elm; |
||
2422 | elm = this.getEl(); |
||
2423 | zoom = this.zoom(); |
||
2424 | rect = this.state.get('rect'); |
||
2425 | $img = this.$el.find('img'); |
||
2426 | $bg = this.$el.find('.mce-imagepanel-bg'); |
||
2427 | pw = elm.offsetWidth; |
||
2428 | ph = elm.offsetHeight; |
||
2429 | w = $img[0].naturalWidth * zoom; |
||
2430 | h = $img[0].naturalHeight * zoom; |
||
2431 | x = Math.max(0, pw / 2 - w / 2); |
||
2432 | y = Math.max(0, ph / 2 - h / 2); |
||
2433 | $img.css({ |
||
2434 | left: x, |
||
2435 | top: y, |
||
2436 | width: w, |
||
2437 | height: h |
||
2438 | }); |
||
2439 | $bg.css({ |
||
2440 | left: x, |
||
2441 | top: y, |
||
2442 | width: w, |
||
2443 | height: h |
||
2444 | }); |
||
2445 | if (this.cropRect) { |
||
2446 | this.cropRect.setRect({ |
||
2447 | x: rect.x * zoom + x, |
||
2448 | y: rect.y * zoom + y, |
||
2449 | w: rect.w * zoom, |
||
2450 | h: rect.h * zoom |
||
2451 | }); |
||
2452 | this.cropRect.setClampRect({ |
||
2453 | x: x, |
||
2454 | y: y, |
||
2455 | w: w, |
||
2456 | h: h |
||
2457 | }); |
||
2458 | this.cropRect.setViewPortRect({ |
||
2459 | x: 0, |
||
2460 | y: 0, |
||
2461 | w: pw, |
||
2462 | h: ph |
||
2463 | }); |
||
2464 | } |
||
2465 | }, |
||
2466 | bindStates: function () { |
||
2467 | var self$$1 = this; |
||
2468 | function setupCropRect(rect) { |
||
2469 | self$$1.cropRect = CropRect(rect, self$$1.state.get('viewRect'), self$$1.state.get('viewRect'), self$$1.getEl(), function () { |
||
2470 | self$$1.fire('crop'); |
||
2471 | }); |
||
2472 | self$$1.cropRect.on('updateRect', function (e) { |
||
2473 | var rect = e.rect; |
||
2474 | var zoom = self$$1.zoom(); |
||
2475 | rect = { |
||
2476 | x: Math.round(rect.x / zoom), |
||
2477 | y: Math.round(rect.y / zoom), |
||
2478 | w: Math.round(rect.w / zoom), |
||
2479 | h: Math.round(rect.h / zoom) |
||
2480 | }; |
||
2481 | self$$1.state.set('rect', rect); |
||
2482 | }); |
||
2483 | self$$1.on('remove', self$$1.cropRect.destroy); |
||
2484 | } |
||
2485 | self$$1.state.on('change:cropEnabled', function (e) { |
||
2486 | self$$1.cropRect.toggleVisibility(e.value); |
||
2487 | self$$1.repaintImage(); |
||
2488 | }); |
||
2489 | self$$1.state.on('change:zoom', function () { |
||
2490 | self$$1.repaintImage(); |
||
2491 | }); |
||
2492 | self$$1.state.on('change:rect', function (e) { |
||
2493 | var rect = e.value; |
||
2494 | if (!self$$1.cropRect) { |
||
2495 | setupCropRect(rect); |
||
2496 | } |
||
2497 | self$$1.cropRect.setRect(rect); |
||
2498 | }); |
||
2499 | } |
||
2500 | }); |
||
2501 | return new ImagePanel(settings); |
||
2502 | }; |
||
2503 | var ImagePanel = { create: create$2 }; |
||
2504 | |||
2505 | function createState(blob) { |
||
2506 | return { |
||
2507 | blob: blob, |
||
2508 | url: URL$1.createObjectURL(blob) |
||
2509 | }; |
||
2510 | } |
||
2511 | function destroyState(state) { |
||
2512 | if (state) { |
||
2513 | URL$1.revokeObjectURL(state.url); |
||
2514 | } |
||
2515 | } |
||
2516 | function destroyStates(states) { |
||
2517 | global$1.each(states, destroyState); |
||
2518 | } |
||
2519 | function open(editor, currentState, resolve, reject) { |
||
2520 | var win, undoStack = UndoStack(), mainPanel, filtersPanel, tempState, cropPanel, resizePanel, flipRotatePanel, imagePanel, sidePanel, mainViewContainer, invertPanel, brightnessPanel, huePanel, saturatePanel, contrastPanel, grayscalePanel, sepiaPanel, colorizePanel, sharpenPanel, embossPanel, gammaPanel, exposurePanel, panels, width, height, ratioW, ratioH; |
||
2521 | var reverseIfRtl = function (items) { |
||
2522 | return editor.rtl ? items.reverse() : items; |
||
2523 | }; |
||
2524 | function recalcSize(e) { |
||
2525 | var widthCtrl, heightCtrl, newWidth, newHeight; |
||
2526 | widthCtrl = win.find('#w')[0]; |
||
2527 | heightCtrl = win.find('#h')[0]; |
||
2528 | newWidth = parseInt(widthCtrl.value(), 10); |
||
2529 | newHeight = parseInt(heightCtrl.value(), 10); |
||
2530 | if (win.find('#constrain')[0].checked() && width && height && newWidth && newHeight) { |
||
2531 | if (e.control.settings.name === 'w') { |
||
2532 | newHeight = Math.round(newWidth * ratioW); |
||
2533 | heightCtrl.value(newHeight); |
||
2534 | } else { |
||
2535 | newWidth = Math.round(newHeight * ratioH); |
||
2536 | widthCtrl.value(newWidth); |
||
2537 | } |
||
2538 | } |
||
2539 | width = newWidth; |
||
2540 | height = newHeight; |
||
2541 | } |
||
2542 | function floatToPercent(value) { |
||
2543 | return Math.round(value * 100) + '%'; |
||
2544 | } |
||
2545 | function updateButtonUndoStates() { |
||
2546 | win.find('#undo').disabled(!undoStack.canUndo()); |
||
2547 | win.find('#redo').disabled(!undoStack.canRedo()); |
||
2548 | win.statusbar.find('#save').disabled(!undoStack.canUndo()); |
||
2549 | } |
||
2550 | function disableUndoRedo() { |
||
2551 | win.find('#undo').disabled(true); |
||
2552 | win.find('#redo').disabled(true); |
||
2553 | } |
||
2554 | function displayState(state) { |
||
2555 | if (state) { |
||
2556 | imagePanel.imageSrc(state.url); |
||
2557 | } |
||
2558 | } |
||
2559 | function switchPanel(targetPanel) { |
||
2560 | return function () { |
||
2561 | var hidePanels = global$1.grep(panels, function (panel) { |
||
2562 | return panel.settings.name !== targetPanel; |
||
2563 | }); |
||
2564 | global$1.each(hidePanels, function (panel) { |
||
2565 | panel.hide(); |
||
2566 | }); |
||
2567 | targetPanel.show(); |
||
2568 | targetPanel.focus(); |
||
2569 | }; |
||
2570 | } |
||
2571 | function addTempState(blob) { |
||
2572 | tempState = createState(blob); |
||
2573 | displayState(tempState); |
||
2574 | } |
||
2575 | function addBlobState(blob) { |
||
2576 | currentState = createState(blob); |
||
2577 | displayState(currentState); |
||
2578 | destroyStates(undoStack.add(currentState).removed); |
||
2579 | updateButtonUndoStates(); |
||
2580 | } |
||
2581 | function crop() { |
||
2582 | var rect = imagePanel.selection(); |
||
2583 | ResultConversions.blobToImageResult(currentState.blob).then(function (ir) { |
||
2584 | ImageTransformations.crop(ir, rect.x, rect.y, rect.w, rect.h).then(imageResultToBlob).then(function (blob) { |
||
2585 | addBlobState(blob); |
||
2586 | cancel(); |
||
2587 | }); |
||
2588 | }); |
||
2589 | } |
||
2590 | var tempAction = function (fn) { |
||
2591 | var args = [].slice.call(arguments, 1); |
||
2592 | return function () { |
||
2593 | var state = tempState || currentState; |
||
2594 | ResultConversions.blobToImageResult(state.blob).then(function (ir) { |
||
2595 | fn.apply(this, [ir].concat(args)).then(imageResultToBlob).then(addTempState); |
||
2596 | }); |
||
2597 | }; |
||
2598 | }; |
||
2599 | function action(fn) { |
||
2600 | var arg = []; |
||
2601 | for (var _i = 1; _i < arguments.length; _i++) { |
||
2602 | arg[_i - 1] = arguments[_i]; |
||
2603 | } |
||
2604 | var args = [].slice.call(arguments, 1); |
||
2605 | return function () { |
||
2606 | ResultConversions.blobToImageResult(currentState.blob).then(function (ir) { |
||
2607 | fn.apply(this, [ir].concat(args)).then(imageResultToBlob).then(addBlobState); |
||
2608 | }); |
||
2609 | }; |
||
2610 | } |
||
2611 | function cancel() { |
||
2612 | displayState(currentState); |
||
2613 | destroyState(tempState); |
||
2614 | switchPanel(mainPanel)(); |
||
2615 | updateButtonUndoStates(); |
||
2616 | } |
||
2617 | function waitForTempState(times, applyCall) { |
||
2618 | if (tempState) { |
||
2619 | applyCall(); |
||
2620 | } else { |
||
2621 | setTimeout(function () { |
||
2622 | if (times-- > 0) { |
||
2623 | waitForTempState(times, applyCall); |
||
2624 | } else { |
||
2625 | editor.windowManager.alert('Error: failed to apply image operation.'); |
||
2626 | } |
||
2627 | }, 10); |
||
2628 | } |
||
2629 | } |
||
2630 | function applyTempState() { |
||
2631 | if (tempState) { |
||
2632 | addBlobState(tempState.blob); |
||
2633 | cancel(); |
||
2634 | } else { |
||
2635 | waitForTempState(100, applyTempState); |
||
2636 | } |
||
2637 | } |
||
2638 | function zoomIn() { |
||
2639 | var zoom = imagePanel.zoom(); |
||
2640 | if (zoom < 2) { |
||
2641 | zoom += 0.1; |
||
2642 | } |
||
2643 | imagePanel.zoom(zoom); |
||
2644 | } |
||
2645 | function zoomOut() { |
||
2646 | var zoom = imagePanel.zoom(); |
||
2647 | if (zoom > 0.1) { |
||
2648 | zoom -= 0.1; |
||
2649 | } |
||
2650 | imagePanel.zoom(zoom); |
||
2651 | } |
||
2652 | function undo() { |
||
2653 | currentState = undoStack.undo(); |
||
2654 | displayState(currentState); |
||
2655 | updateButtonUndoStates(); |
||
2656 | } |
||
2657 | function redo() { |
||
2658 | currentState = undoStack.redo(); |
||
2659 | displayState(currentState); |
||
2660 | updateButtonUndoStates(); |
||
2661 | } |
||
2662 | function save() { |
||
2663 | resolve(currentState.blob); |
||
2664 | win.close(); |
||
2665 | } |
||
2666 | function createPanel(items) { |
||
2667 | return global$6.create('Form', { |
||
2668 | layout: 'flex', |
||
2669 | direction: 'row', |
||
2670 | labelGap: 5, |
||
2671 | border: '0 0 1 0', |
||
2672 | align: 'center', |
||
2673 | pack: 'center', |
||
2674 | padding: '0 10 0 10', |
||
2675 | spacing: 5, |
||
2676 | flex: 0, |
||
2677 | minHeight: 60, |
||
2678 | defaults: { |
||
2679 | classes: 'imagetool', |
||
2680 | type: 'button' |
||
2681 | }, |
||
2682 | items: items |
||
2683 | }); |
||
2684 | } |
||
2685 | var imageResultToBlob = function (ir) { |
||
2686 | return ir.toBlob(); |
||
2687 | }; |
||
2688 | function createFilterPanel(title, filter) { |
||
2689 | return createPanel(reverseIfRtl([ |
||
2690 | { |
||
2691 | text: 'Back', |
||
2692 | onclick: cancel |
||
2693 | }, |
||
2694 | { |
||
2695 | type: 'spacer', |
||
2696 | flex: 1 |
||
2697 | }, |
||
2698 | { |
||
2699 | text: 'Apply', |
||
2700 | subtype: 'primary', |
||
2701 | onclick: applyTempState |
||
2702 | } |
||
2703 | ])).hide().on('show', function () { |
||
2704 | disableUndoRedo(); |
||
2705 | ResultConversions.blobToImageResult(currentState.blob).then(function (ir) { |
||
2706 | return filter(ir); |
||
2707 | }).then(imageResultToBlob).then(function (blob) { |
||
2708 | var newTempState = createState(blob); |
||
2709 | displayState(newTempState); |
||
2710 | destroyState(tempState); |
||
2711 | tempState = newTempState; |
||
2712 | }); |
||
2713 | }); |
||
2714 | } |
||
2715 | function createVariableFilterPanel(title, filter, value, min, max) { |
||
2716 | function update(value) { |
||
2717 | ResultConversions.blobToImageResult(currentState.blob).then(function (ir) { |
||
2718 | return filter(ir, value); |
||
2719 | }).then(imageResultToBlob).then(function (blob) { |
||
2720 | var newTempState = createState(blob); |
||
2721 | displayState(newTempState); |
||
2722 | destroyState(tempState); |
||
2723 | tempState = newTempState; |
||
2724 | }); |
||
2725 | } |
||
2726 | return createPanel(reverseIfRtl([ |
||
2727 | { |
||
2728 | text: 'Back', |
||
2729 | onclick: cancel |
||
2730 | }, |
||
2731 | { |
||
2732 | type: 'spacer', |
||
2733 | flex: 1 |
||
2734 | }, |
||
2735 | { |
||
2736 | type: 'slider', |
||
2737 | flex: 1, |
||
2738 | ondragend: function (e) { |
||
2739 | update(e.value); |
||
2740 | }, |
||
2741 | minValue: editor.rtl ? max : min, |
||
2742 | maxValue: editor.rtl ? min : max, |
||
2743 | value: value, |
||
2744 | previewFilter: floatToPercent |
||
2745 | }, |
||
2746 | { |
||
2747 | type: 'spacer', |
||
2748 | flex: 1 |
||
2749 | }, |
||
2750 | { |
||
2751 | text: 'Apply', |
||
2752 | subtype: 'primary', |
||
2753 | onclick: applyTempState |
||
2754 | } |
||
2755 | ])).hide().on('show', function () { |
||
2756 | this.find('slider').value(value); |
||
2757 | disableUndoRedo(); |
||
2758 | }); |
||
2759 | } |
||
2760 | function createRgbFilterPanel(title, filter) { |
||
2761 | function update() { |
||
2762 | var r, g, b; |
||
2763 | r = win.find('#r')[0].value(); |
||
2764 | g = win.find('#g')[0].value(); |
||
2765 | b = win.find('#b')[0].value(); |
||
2766 | ResultConversions.blobToImageResult(currentState.blob).then(function (ir) { |
||
2767 | return filter(ir, r, g, b); |
||
2768 | }).then(imageResultToBlob).then(function (blob) { |
||
2769 | var newTempState = createState(blob); |
||
2770 | displayState(newTempState); |
||
2771 | destroyState(tempState); |
||
2772 | tempState = newTempState; |
||
2773 | }); |
||
2774 | } |
||
2775 | var min = editor.rtl ? 2 : 0; |
||
2776 | var max = editor.rtl ? 0 : 2; |
||
2777 | return createPanel(reverseIfRtl([ |
||
2778 | { |
||
2779 | text: 'Back', |
||
2780 | onclick: cancel |
||
2781 | }, |
||
2782 | { |
||
2783 | type: 'spacer', |
||
2784 | flex: 1 |
||
2785 | }, |
||
2786 | { |
||
2787 | type: 'slider', |
||
2788 | label: 'R', |
||
2789 | name: 'r', |
||
2790 | minValue: min, |
||
2791 | value: 1, |
||
2792 | maxValue: max, |
||
2793 | ondragend: update, |
||
2794 | previewFilter: floatToPercent |
||
2795 | }, |
||
2796 | { |
||
2797 | type: 'slider', |
||
2798 | label: 'G', |
||
2799 | name: 'g', |
||
2800 | minValue: min, |
||
2801 | value: 1, |
||
2802 | maxValue: max, |
||
2803 | ondragend: update, |
||
2804 | previewFilter: floatToPercent |
||
2805 | }, |
||
2806 | { |
||
2807 | type: 'slider', |
||
2808 | label: 'B', |
||
2809 | name: 'b', |
||
2810 | minValue: min, |
||
2811 | value: 1, |
||
2812 | maxValue: max, |
||
2813 | ondragend: update, |
||
2814 | previewFilter: floatToPercent |
||
2815 | }, |
||
2816 | { |
||
2817 | type: 'spacer', |
||
2818 | flex: 1 |
||
2819 | }, |
||
2820 | { |
||
2821 | text: 'Apply', |
||
2822 | subtype: 'primary', |
||
2823 | onclick: applyTempState |
||
2824 | } |
||
2825 | ])).hide().on('show', function () { |
||
2826 | win.find('#r,#g,#b').value(1); |
||
2827 | disableUndoRedo(); |
||
2828 | }); |
||
2829 | } |
||
2830 | cropPanel = createPanel(reverseIfRtl([ |
||
2831 | { |
||
2832 | text: 'Back', |
||
2833 | onclick: cancel |
||
2834 | }, |
||
2835 | { |
||
2836 | type: 'spacer', |
||
2837 | flex: 1 |
||
2838 | }, |
||
2839 | { |
||
2840 | text: 'Apply', |
||
2841 | subtype: 'primary', |
||
2842 | onclick: crop |
||
2843 | } |
||
2844 | ])).hide().on('show hide', function (e) { |
||
2845 | imagePanel.toggleCropRect(e.type === 'show'); |
||
2846 | }).on('show', disableUndoRedo); |
||
2847 | function toggleConstrain(e) { |
||
2848 | if (e.control.value() === true) { |
||
2849 | ratioW = height / width; |
||
2850 | ratioH = width / height; |
||
2851 | } |
||
2852 | } |
||
2853 | resizePanel = createPanel(reverseIfRtl([ |
||
2854 | { |
||
2855 | text: 'Back', |
||
2856 | onclick: cancel |
||
2857 | }, |
||
2858 | { |
||
2859 | type: 'spacer', |
||
2860 | flex: 1 |
||
2861 | }, |
||
2862 | { |
||
2863 | type: 'textbox', |
||
2864 | name: 'w', |
||
2865 | label: 'Width', |
||
2866 | size: 4, |
||
2867 | onkeyup: recalcSize |
||
2868 | }, |
||
2869 | { |
||
2870 | type: 'textbox', |
||
2871 | name: 'h', |
||
2872 | label: 'Height', |
||
2873 | size: 4, |
||
2874 | onkeyup: recalcSize |
||
2875 | }, |
||
2876 | { |
||
2877 | type: 'checkbox', |
||
2878 | name: 'constrain', |
||
2879 | text: 'Constrain proportions', |
||
2880 | checked: true, |
||
2881 | onchange: toggleConstrain |
||
2882 | }, |
||
2883 | { |
||
2884 | type: 'spacer', |
||
2885 | flex: 1 |
||
2886 | }, |
||
2887 | { |
||
2888 | text: 'Apply', |
||
2889 | subtype: 'primary', |
||
2890 | onclick: 'submit' |
||
2891 | } |
||
2892 | ])).hide().on('submit', function (e) { |
||
2893 | var width = parseInt(win.find('#w').value(), 10), height = parseInt(win.find('#h').value(), 10); |
||
2894 | e.preventDefault(); |
||
2895 | action(ImageTransformations.resize, width, height)(); |
||
2896 | cancel(); |
||
2897 | }).on('show', disableUndoRedo); |
||
2898 | flipRotatePanel = createPanel(reverseIfRtl([ |
||
2899 | { |
||
2900 | text: 'Back', |
||
2901 | onclick: cancel |
||
2902 | }, |
||
2903 | { |
||
2904 | type: 'spacer', |
||
2905 | flex: 1 |
||
2906 | }, |
||
2907 | { |
||
2908 | icon: 'fliph', |
||
2909 | tooltip: 'Flip horizontally', |
||
2910 | onclick: tempAction(ImageTransformations.flip, 'h') |
||
2911 | }, |
||
2912 | { |
||
2913 | icon: 'flipv', |
||
2914 | tooltip: 'Flip vertically', |
||
2915 | onclick: tempAction(ImageTransformations.flip, 'v') |
||
2916 | }, |
||
2917 | { |
||
2918 | icon: 'rotateleft', |
||
2919 | tooltip: 'Rotate counterclockwise', |
||
2920 | onclick: tempAction(ImageTransformations.rotate, -90) |
||
2921 | }, |
||
2922 | { |
||
2923 | icon: 'rotateright', |
||
2924 | tooltip: 'Rotate clockwise', |
||
2925 | onclick: tempAction(ImageTransformations.rotate, 90) |
||
2926 | }, |
||
2927 | { |
||
2928 | type: 'spacer', |
||
2929 | flex: 1 |
||
2930 | }, |
||
2931 | { |
||
2932 | text: 'Apply', |
||
2933 | subtype: 'primary', |
||
2934 | onclick: applyTempState |
||
2935 | } |
||
2936 | ])).hide().on('show', disableUndoRedo); |
||
2937 | invertPanel = createFilterPanel('Invert', ImageTransformations.invert); |
||
2938 | sharpenPanel = createFilterPanel('Sharpen', ImageTransformations.sharpen); |
||
2939 | embossPanel = createFilterPanel('Emboss', ImageTransformations.emboss); |
||
2940 | brightnessPanel = createVariableFilterPanel('Brightness', ImageTransformations.brightness, 0, -1, 1); |
||
2941 | huePanel = createVariableFilterPanel('Hue', ImageTransformations.hue, 180, 0, 360); |
||
2942 | saturatePanel = createVariableFilterPanel('Saturate', ImageTransformations.saturate, 0, -1, 1); |
||
2943 | contrastPanel = createVariableFilterPanel('Contrast', ImageTransformations.contrast, 0, -1, 1); |
||
2944 | grayscalePanel = createVariableFilterPanel('Grayscale', ImageTransformations.grayscale, 0, 0, 1); |
||
2945 | sepiaPanel = createVariableFilterPanel('Sepia', ImageTransformations.sepia, 0, 0, 1); |
||
2946 | colorizePanel = createRgbFilterPanel('Colorize', ImageTransformations.colorize); |
||
2947 | gammaPanel = createVariableFilterPanel('Gamma', ImageTransformations.gamma, 0, -1, 1); |
||
2948 | exposurePanel = createVariableFilterPanel('Exposure', ImageTransformations.exposure, 1, 0, 2); |
||
2949 | filtersPanel = createPanel(reverseIfRtl([ |
||
2950 | { |
||
2951 | text: 'Back', |
||
2952 | onclick: cancel |
||
2953 | }, |
||
2954 | { |
||
2955 | type: 'spacer', |
||
2956 | flex: 1 |
||
2957 | }, |
||
2958 | { |
||
2959 | text: 'hue', |
||
2960 | icon: 'hue', |
||
2961 | onclick: switchPanel(huePanel) |
||
2962 | }, |
||
2963 | { |
||
2964 | text: 'saturate', |
||
2965 | icon: 'saturate', |
||
2966 | onclick: switchPanel(saturatePanel) |
||
2967 | }, |
||
2968 | { |
||
2969 | text: 'sepia', |
||
2970 | icon: 'sepia', |
||
2971 | onclick: switchPanel(sepiaPanel) |
||
2972 | }, |
||
2973 | { |
||
2974 | text: 'emboss', |
||
2975 | icon: 'emboss', |
||
2976 | onclick: switchPanel(embossPanel) |
||
2977 | }, |
||
2978 | { |
||
2979 | text: 'exposure', |
||
2980 | icon: 'exposure', |
||
2981 | onclick: switchPanel(exposurePanel) |
||
2982 | }, |
||
2983 | { |
||
2984 | type: 'spacer', |
||
2985 | flex: 1 |
||
2986 | } |
||
2987 | ])).hide(); |
||
2988 | mainPanel = createPanel(reverseIfRtl([ |
||
2989 | { |
||
2990 | tooltip: 'Crop', |
||
2991 | icon: 'crop', |
||
2992 | onclick: switchPanel(cropPanel) |
||
2993 | }, |
||
2994 | { |
||
2995 | tooltip: 'Resize', |
||
2996 | icon: 'resize2', |
||
2997 | onclick: switchPanel(resizePanel) |
||
2998 | }, |
||
2999 | { |
||
3000 | tooltip: 'Orientation', |
||
3001 | icon: 'orientation', |
||
3002 | onclick: switchPanel(flipRotatePanel) |
||
3003 | }, |
||
3004 | { |
||
3005 | tooltip: 'Brightness', |
||
3006 | icon: 'sun', |
||
3007 | onclick: switchPanel(brightnessPanel) |
||
3008 | }, |
||
3009 | { |
||
3010 | tooltip: 'Sharpen', |
||
3011 | icon: 'sharpen', |
||
3012 | onclick: switchPanel(sharpenPanel) |
||
3013 | }, |
||
3014 | { |
||
3015 | tooltip: 'Contrast', |
||
3016 | icon: 'contrast', |
||
3017 | onclick: switchPanel(contrastPanel) |
||
3018 | }, |
||
3019 | { |
||
3020 | tooltip: 'Color levels', |
||
3021 | icon: 'drop', |
||
3022 | onclick: switchPanel(colorizePanel) |
||
3023 | }, |
||
3024 | { |
||
3025 | tooltip: 'Gamma', |
||
3026 | icon: 'gamma', |
||
3027 | onclick: switchPanel(gammaPanel) |
||
3028 | }, |
||
3029 | { |
||
3030 | tooltip: 'Invert', |
||
3031 | icon: 'invert', |
||
3032 | onclick: switchPanel(invertPanel) |
||
3033 | } |
||
3034 | ])); |
||
3035 | imagePanel = ImagePanel.create({ |
||
3036 | flex: 1, |
||
3037 | imageSrc: currentState.url |
||
3038 | }); |
||
3039 | sidePanel = global$6.create('Container', { |
||
3040 | layout: 'flex', |
||
3041 | direction: 'column', |
||
3042 | pack: 'start', |
||
3043 | border: '0 1 0 0', |
||
3044 | padding: 5, |
||
3045 | spacing: 5, |
||
3046 | items: [ |
||
3047 | { |
||
3048 | type: 'button', |
||
3049 | icon: 'undo', |
||
3050 | tooltip: 'Undo', |
||
3051 | name: 'undo', |
||
3052 | onclick: undo |
||
3053 | }, |
||
3054 | { |
||
3055 | type: 'button', |
||
3056 | icon: 'redo', |
||
3057 | tooltip: 'Redo', |
||
3058 | name: 'redo', |
||
3059 | onclick: redo |
||
3060 | }, |
||
3061 | { |
||
3062 | type: 'button', |
||
3063 | icon: 'zoomin', |
||
3064 | tooltip: 'Zoom in', |
||
3065 | onclick: zoomIn |
||
3066 | }, |
||
3067 | { |
||
3068 | type: 'button', |
||
3069 | icon: 'zoomout', |
||
3070 | tooltip: 'Zoom out', |
||
3071 | onclick: zoomOut |
||
3072 | } |
||
3073 | ] |
||
3074 | }); |
||
3075 | mainViewContainer = global$6.create('Container', { |
||
3076 | type: 'container', |
||
3077 | layout: 'flex', |
||
3078 | direction: 'row', |
||
3079 | align: 'stretch', |
||
3080 | flex: 1, |
||
3081 | items: reverseIfRtl([ |
||
3082 | sidePanel, |
||
3083 | imagePanel |
||
3084 | ]) |
||
3085 | }); |
||
3086 | panels = [ |
||
3087 | mainPanel, |
||
3088 | cropPanel, |
||
3089 | resizePanel, |
||
3090 | flipRotatePanel, |
||
3091 | filtersPanel, |
||
3092 | invertPanel, |
||
3093 | brightnessPanel, |
||
3094 | huePanel, |
||
3095 | saturatePanel, |
||
3096 | contrastPanel, |
||
3097 | grayscalePanel, |
||
3098 | sepiaPanel, |
||
3099 | colorizePanel, |
||
3100 | sharpenPanel, |
||
3101 | embossPanel, |
||
3102 | gammaPanel, |
||
3103 | exposurePanel |
||
3104 | ]; |
||
3105 | win = editor.windowManager.open({ |
||
3106 | layout: 'flex', |
||
3107 | direction: 'column', |
||
3108 | align: 'stretch', |
||
3109 | minWidth: Math.min(global$5.DOM.getViewPort().w, 800), |
||
3110 | minHeight: Math.min(global$5.DOM.getViewPort().h, 650), |
||
3111 | title: 'Edit image', |
||
3112 | items: panels.concat([mainViewContainer]), |
||
3113 | buttons: reverseIfRtl([ |
||
3114 | { |
||
3115 | text: 'Save', |
||
3116 | name: 'save', |
||
3117 | subtype: 'primary', |
||
3118 | onclick: save |
||
3119 | }, |
||
3120 | { |
||
3121 | text: 'Cancel', |
||
3122 | onclick: 'close' |
||
3123 | } |
||
3124 | ]) |
||
3125 | }); |
||
3126 | win.on('close', function () { |
||
3127 | reject(); |
||
3128 | destroyStates(undoStack.data); |
||
3129 | undoStack = null; |
||
3130 | tempState = null; |
||
3131 | }); |
||
3132 | undoStack.add(currentState); |
||
3133 | updateButtonUndoStates(); |
||
3134 | imagePanel.on('load', function () { |
||
3135 | width = imagePanel.imageSize().w; |
||
3136 | height = imagePanel.imageSize().h; |
||
3137 | ratioW = height / width; |
||
3138 | ratioH = width / height; |
||
3139 | win.find('#w').value(width); |
||
3140 | win.find('#h').value(height); |
||
3141 | }); |
||
3142 | imagePanel.on('crop', crop); |
||
3143 | } |
||
3144 | function edit(editor, imageResult) { |
||
3145 | return new global$3(function (resolve, reject) { |
||
3146 | return imageResult.toBlob().then(function (blob) { |
||
3147 | open(editor, createState(blob), resolve, reject); |
||
3148 | }); |
||
3149 | }); |
||
3150 | } |
||
3151 | var Dialog = { edit: edit }; |
||
3152 | |||
3153 | function getImageSize(img) { |
||
3154 | var width, height; |
||
3155 | function isPxValue(value) { |
||
3156 | return /^[0-9\.]+px$/.test(value); |
||
3157 | } |
||
3158 | width = img.style.width; |
||
3159 | height = img.style.height; |
||
3160 | if (width || height) { |
||
3161 | if (isPxValue(width) && isPxValue(height)) { |
||
3162 | return { |
||
3163 | w: parseInt(width, 10), |
||
3164 | h: parseInt(height, 10) |
||
3165 | }; |
||
3166 | } |
||
3167 | return null; |
||
3168 | } |
||
3169 | width = img.width; |
||
3170 | height = img.height; |
||
3171 | if (width && height) { |
||
3172 | return { |
||
3173 | w: parseInt(width, 10), |
||
3174 | h: parseInt(height, 10) |
||
3175 | }; |
||
3176 | } |
||
3177 | return null; |
||
3178 | } |
||
3179 | function setImageSize(img, size) { |
||
3180 | var width, height; |
||
3181 | if (size) { |
||
3182 | width = img.style.width; |
||
3183 | height = img.style.height; |
||
3184 | if (width || height) { |
||
3185 | img.style.width = size.w + 'px'; |
||
3186 | img.style.height = size.h + 'px'; |
||
3187 | img.removeAttribute('data-mce-style'); |
||
3188 | } |
||
3189 | width = img.width; |
||
3190 | height = img.height; |
||
3191 | if (width || height) { |
||
3192 | img.setAttribute('width', size.w); |
||
3193 | img.setAttribute('height', size.h); |
||
3194 | } |
||
3195 | } |
||
3196 | } |
||
3197 | function getNaturalImageSize(img) { |
||
3198 | return { |
||
3199 | w: img.naturalWidth, |
||
3200 | h: img.naturalHeight |
||
3201 | }; |
||
3202 | } |
||
3203 | var ImageSize$1 = { |
||
3204 | getImageSize: getImageSize, |
||
3205 | setImageSize: setImageSize, |
||
3206 | getNaturalImageSize: getNaturalImageSize |
||
3207 | }; |
||
3208 | |||
3209 | var typeOf = function (x) { |
||
3210 | if (x === null) |
||
3211 | return 'null'; |
||
3212 | var t = typeof x; |
||
3213 | if (t === 'object' && Array.prototype.isPrototypeOf(x)) |
||
3214 | return 'array'; |
||
3215 | if (t === 'object' && String.prototype.isPrototypeOf(x)) |
||
3216 | return 'string'; |
||
3217 | return t; |
||
3218 | }; |
||
3219 | var isType = function (type) { |
||
3220 | return function (value) { |
||
3221 | return typeOf(value) === type; |
||
3222 | }; |
||
3223 | }; |
||
3224 | var isFunction = isType('function'); |
||
3225 | |||
3226 | var find = function (xs, pred) { |
||
3227 | for (var i = 0, len = xs.length; i < len; i++) { |
||
3228 | var x = xs[i]; |
||
3229 | if (pred(x, i, xs)) { |
||
3230 | return Option.some(x); |
||
3231 | } |
||
3232 | } |
||
3233 | return Option.none(); |
||
3234 | }; |
||
3235 | var slice = Array.prototype.slice; |
||
3236 | var from$1 = isFunction(Array.from) ? Array.from : function (x) { |
||
3237 | return slice.call(x); |
||
3238 | }; |
||
3239 | |||
3240 | function XMLHttpRequest$1 () { |
||
3241 | var f = Global$1.getOrDie('XMLHttpRequest'); |
||
3242 | return new f(); |
||
3243 | } |
||
3244 | |||
3245 | var isValue = function (obj) { |
||
3246 | return obj !== null && obj !== undefined; |
||
3247 | }; |
||
3248 | var traverse = function (json, path) { |
||
3249 | var value; |
||
3250 | value = path.reduce(function (result, key) { |
||
3251 | return isValue(result) ? result[key] : undefined; |
||
3252 | }, json); |
||
3253 | return isValue(value) ? value : null; |
||
3254 | }; |
||
3255 | var requestUrlAsBlob = function (url, headers, withCredentials) { |
||
3256 | return new global$3(function (resolve) { |
||
3257 | var xhr; |
||
3258 | xhr = XMLHttpRequest$1(); |
||
3259 | xhr.onreadystatechange = function () { |
||
3260 | if (xhr.readyState === 4) { |
||
3261 | resolve({ |
||
3262 | status: xhr.status, |
||
3263 | blob: this.response |
||
3264 | }); |
||
3265 | } |
||
3266 | }; |
||
3267 | xhr.open('GET', url, true); |
||
3268 | xhr.withCredentials = withCredentials; |
||
3269 | global$1.each(headers, function (value, key) { |
||
3270 | xhr.setRequestHeader(key, value); |
||
3271 | }); |
||
3272 | xhr.responseType = 'blob'; |
||
3273 | xhr.send(); |
||
3274 | }); |
||
3275 | }; |
||
3276 | var readBlob = function (blob) { |
||
3277 | return new global$3(function (resolve) { |
||
3278 | var fr = FileReader(); |
||
3279 | fr.onload = function (e) { |
||
3280 | var data = e.target; |
||
3281 | resolve(data.result); |
||
3282 | }; |
||
3283 | fr.readAsText(blob); |
||
3284 | }); |
||
3285 | }; |
||
3286 | var parseJson = function (text) { |
||
3287 | var json; |
||
3288 | try { |
||
3289 | json = JSON.parse(text); |
||
3290 | } catch (ex) { |
||
3291 | } |
||
3292 | return json; |
||
3293 | }; |
||
3294 | var Utils = { |
||
3295 | traverse: traverse, |
||
3296 | readBlob: readBlob, |
||
3297 | requestUrlAsBlob: requestUrlAsBlob, |
||
3298 | parseJson: parseJson |
||
3299 | }; |
||
3300 | |||
3301 | var friendlyHttpErrors = [ |
||
3302 | { |
||
3303 | code: 404, |
||
3304 | message: 'Could not find Image Proxy' |
||
3305 | }, |
||
3306 | { |
||
3307 | code: 403, |
||
3308 | message: 'Rejected request' |
||
3309 | }, |
||
3310 | { |
||
3311 | code: 0, |
||
3312 | message: 'Incorrect Image Proxy URL' |
||
3313 | } |
||
3314 | ]; |
||
3315 | var friendlyServiceErrors = [ |
||
3316 | { |
||
3317 | type: 'key_missing', |
||
3318 | message: 'The request did not include an api key.' |
||
3319 | }, |
||
3320 | { |
||
3321 | type: 'key_not_found', |
||
3322 | message: 'The provided api key could not be found.' |
||
3323 | }, |
||
3324 | { |
||
3325 | type: 'domain_not_trusted', |
||
3326 | message: 'The api key is not valid for the request origins.' |
||
3327 | } |
||
3328 | ]; |
||
3329 | var isServiceErrorCode = function (code) { |
||
3330 | return code === 400 || code === 403 || code === 500; |
||
3331 | }; |
||
3332 | var getHttpErrorMsg = function (status) { |
||
3333 | var message = find(friendlyHttpErrors, function (error) { |
||
3334 | return status === error.code; |
||
3335 | }).fold(constant('Unknown ImageProxy error'), function (error) { |
||
3336 | return error.message; |
||
3337 | }); |
||
3338 | return 'ImageProxy HTTP error: ' + message; |
||
3339 | }; |
||
3340 | var handleHttpError = function (status) { |
||
3341 | var message = getHttpErrorMsg(status); |
||
3342 | return global$3.reject(message); |
||
3343 | }; |
||
3344 | var getServiceErrorMsg = function (type) { |
||
3345 | return find(friendlyServiceErrors, function (error) { |
||
3346 | return error.type === type; |
||
3347 | }).fold(constant('Unknown service error'), function (error) { |
||
3348 | return error.message; |
||
3349 | }); |
||
3350 | }; |
||
3351 | var getServiceError = function (text) { |
||
3352 | var serviceError = Utils.parseJson(text); |
||
3353 | var errorType = Utils.traverse(serviceError, [ |
||
3354 | 'error', |
||
3355 | 'type' |
||
3356 | ]); |
||
3357 | var errorMsg = errorType ? getServiceErrorMsg(errorType) : 'Invalid JSON in service error message'; |
||
3358 | return 'ImageProxy Service error: ' + errorMsg; |
||
3359 | }; |
||
3360 | var handleServiceError = function (status, blob) { |
||
3361 | return Utils.readBlob(blob).then(function (text) { |
||
3362 | var serviceError = getServiceError(text); |
||
3363 | return global$3.reject(serviceError); |
||
3364 | }); |
||
3365 | }; |
||
3366 | var handleServiceErrorResponse = function (status, blob) { |
||
3367 | return isServiceErrorCode(status) ? handleServiceError(status, blob) : handleHttpError(status); |
||
3368 | }; |
||
3369 | var Errors = { |
||
3370 | handleServiceErrorResponse: handleServiceErrorResponse, |
||
3371 | handleHttpError: handleHttpError, |
||
3372 | getHttpErrorMsg: getHttpErrorMsg, |
||
3373 | getServiceErrorMsg: getServiceErrorMsg |
||
3374 | }; |
||
3375 | |||
3376 | var appendApiKey = function (url, apiKey) { |
||
3377 | var separator = url.indexOf('?') === -1 ? '?' : '&'; |
||
3378 | if (/[?&]apiKey=/.test(url) || !apiKey) { |
||
3379 | return url; |
||
3380 | } else { |
||
3381 | return url + separator + 'apiKey=' + encodeURIComponent(apiKey); |
||
3382 | } |
||
3383 | }; |
||
3384 | var requestServiceBlob = function (url, apiKey) { |
||
3385 | var headers = { |
||
3386 | 'Content-Type': 'application/json;charset=UTF-8', |
||
3387 | 'tiny-api-key': apiKey |
||
3388 | }; |
||
3389 | return Utils.requestUrlAsBlob(appendApiKey(url, apiKey), headers, false).then(function (result) { |
||
3390 | return result.status < 200 || result.status >= 300 ? Errors.handleServiceErrorResponse(result.status, result.blob) : global$3.resolve(result.blob); |
||
3391 | }); |
||
3392 | }; |
||
3393 | function requestBlob(url, withCredentials) { |
||
3394 | return Utils.requestUrlAsBlob(url, {}, withCredentials).then(function (result) { |
||
3395 | return result.status < 200 || result.status >= 300 ? Errors.handleHttpError(result.status) : global$3.resolve(result.blob); |
||
3396 | }); |
||
3397 | } |
||
3398 | var getUrl = function (url, apiKey, withCredentials) { |
||
3399 | return apiKey ? requestServiceBlob(url, apiKey) : requestBlob(url, withCredentials); |
||
3400 | }; |
||
3401 | var Proxy = { getUrl: getUrl }; |
||
3402 | |||
3403 | var count$1 = 0; |
||
3404 | var isEditableImage = function (editor, img) { |
||
3405 | var selectorMatched = editor.dom.is(img, 'img:not([data-mce-object],[data-mce-placeholder])'); |
||
3406 | return selectorMatched && (isLocalImage(editor, img) || isCorsImage(editor, img) || editor.settings.imagetools_proxy); |
||
3407 | }; |
||
3408 | var displayError = function (editor, error) { |
||
3409 | editor.notificationManager.open({ |
||
3410 | text: error, |
||
3411 | type: 'error' |
||
3412 | }); |
||
3413 | }; |
||
3414 | var getSelectedImage = function (editor) { |
||
3415 | return editor.selection.getNode(); |
||
3416 | }; |
||
3417 | var extractFilename = function (editor, url) { |
||
3418 | var m = url.match(/\/([^\/\?]+)?\.(?:jpeg|jpg|png|gif)(?:\?|$)/i); |
||
3419 | if (m) { |
||
3420 | return editor.dom.encode(m[1]); |
||
3421 | } |
||
3422 | return null; |
||
3423 | }; |
||
3424 | var createId = function () { |
||
3425 | return 'imagetools' + count$1++; |
||
3426 | }; |
||
3427 | var isLocalImage = function (editor, img) { |
||
3428 | var url = img.src; |
||
3429 | return url.indexOf('data:') === 0 || url.indexOf('blob:') === 0 || new global$4(url).host === editor.documentBaseURI.host; |
||
3430 | }; |
||
3431 | var isCorsImage = function (editor, img) { |
||
3432 | return global$1.inArray(getCorsHosts(editor), new global$4(img.src).host) !== -1; |
||
3433 | }; |
||
3434 | var isCorsWithCredentialsImage = function (editor, img) { |
||
3435 | return global$1.inArray(getCredentialsHosts(editor), new global$4(img.src).host) !== -1; |
||
3436 | }; |
||
3437 | var imageToBlob$2 = function (editor, img) { |
||
3438 | var src = img.src, apiKey; |
||
3439 | if (isCorsImage(editor, img)) { |
||
3440 | return Proxy.getUrl(img.src, null, isCorsWithCredentialsImage(editor, img)); |
||
3441 | } |
||
3442 | if (!isLocalImage(editor, img)) { |
||
3443 | src = getProxyUrl(editor); |
||
3444 | src += (src.indexOf('?') === -1 ? '?' : '&') + 'url=' + encodeURIComponent(img.src); |
||
3445 | apiKey = getApiKey(editor); |
||
3446 | return Proxy.getUrl(src, apiKey, false); |
||
3447 | } |
||
3448 | return BlobConversions.imageToBlob(img); |
||
3449 | }; |
||
3450 | var findSelectedBlob = function (editor) { |
||
3451 | var blobInfo; |
||
3452 | blobInfo = editor.editorUpload.blobCache.getByUri(getSelectedImage(editor).src); |
||
3453 | if (blobInfo) { |
||
3454 | return global$3.resolve(blobInfo.blob()); |
||
3455 | } |
||
3456 | return imageToBlob$2(editor, getSelectedImage(editor)); |
||
3457 | }; |
||
3458 | var startTimedUpload = function (editor, imageUploadTimerState) { |
||
3459 | var imageUploadTimer = global$2.setEditorTimeout(editor, function () { |
||
3460 | editor.editorUpload.uploadImagesAuto(); |
||
3461 | }, getUploadTimeout(editor)); |
||
3462 | imageUploadTimerState.set(imageUploadTimer); |
||
3463 | }; |
||
3464 | var cancelTimedUpload = function (imageUploadTimerState) { |
||
3465 | clearTimeout(imageUploadTimerState.get()); |
||
3466 | }; |
||
3467 | var updateSelectedImage = function (editor, ir, uploadImmediately, imageUploadTimerState, size) { |
||
3468 | return ir.toBlob().then(function (blob) { |
||
3469 | var uri, name, blobCache, blobInfo, selectedImage; |
||
3470 | blobCache = editor.editorUpload.blobCache; |
||
3471 | selectedImage = getSelectedImage(editor); |
||
3472 | uri = selectedImage.src; |
||
3473 | if (shouldReuseFilename(editor)) { |
||
3474 | blobInfo = blobCache.getByUri(uri); |
||
3475 | if (blobInfo) { |
||
3476 | uri = blobInfo.uri(); |
||
3477 | name = blobInfo.name(); |
||
3478 | } else { |
||
3479 | name = extractFilename(editor, uri); |
||
3480 | } |
||
3481 | } |
||
3482 | blobInfo = blobCache.create({ |
||
3483 | id: createId(), |
||
3484 | blob: blob, |
||
3485 | base64: ir.toBase64(), |
||
3486 | uri: uri, |
||
3487 | name: name |
||
3488 | }); |
||
3489 | blobCache.add(blobInfo); |
||
3490 | editor.undoManager.transact(function () { |
||
3491 | function imageLoadedHandler() { |
||
3492 | editor.$(selectedImage).off('load', imageLoadedHandler); |
||
3493 | editor.nodeChanged(); |
||
3494 | if (uploadImmediately) { |
||
3495 | editor.editorUpload.uploadImagesAuto(); |
||
3496 | } else { |
||
3497 | cancelTimedUpload(imageUploadTimerState); |
||
3498 | startTimedUpload(editor, imageUploadTimerState); |
||
3499 | } |
||
3500 | } |
||
3501 | editor.$(selectedImage).on('load', imageLoadedHandler); |
||
3502 | if (size) { |
||
3503 | editor.$(selectedImage).attr({ |
||
3504 | width: size.w, |
||
3505 | height: size.h |
||
3506 | }); |
||
3507 | } |
||
3508 | editor.$(selectedImage).attr({ src: blobInfo.blobUri() }).removeAttr('data-mce-src'); |
||
3509 | }); |
||
3510 | return blobInfo; |
||
3511 | }); |
||
3512 | }; |
||
3513 | var selectedImageOperation = function (editor, imageUploadTimerState, fn, size) { |
||
3514 | return function () { |
||
3515 | return editor._scanForImages().then(curry(findSelectedBlob, editor)).then(ResultConversions.blobToImageResult).then(fn).then(function (imageResult) { |
||
3516 | return updateSelectedImage(editor, imageResult, false, imageUploadTimerState, size); |
||
3517 | }, function (error) { |
||
3518 | displayError(editor, error); |
||
3519 | }); |
||
3520 | }; |
||
3521 | }; |
||
3522 | var rotate$2 = function (editor, imageUploadTimerState, angle) { |
||
3523 | return function () { |
||
3524 | var size = ImageSize$1.getImageSize(getSelectedImage(editor)); |
||
3525 | var flippedSize = size ? { |
||
3526 | w: size.h, |
||
3527 | h: size.w |
||
3528 | } : null; |
||
3529 | return selectedImageOperation(editor, imageUploadTimerState, function (imageResult) { |
||
3530 | return ImageTransformations.rotate(imageResult, angle); |
||
3531 | }, flippedSize)(); |
||
3532 | }; |
||
3533 | }; |
||
3534 | var flip$2 = function (editor, imageUploadTimerState, axis) { |
||
3535 | return function () { |
||
3536 | return selectedImageOperation(editor, imageUploadTimerState, function (imageResult) { |
||
3537 | return ImageTransformations.flip(imageResult, axis); |
||
3538 | })(); |
||
3539 | }; |
||
3540 | }; |
||
3541 | var editImageDialog = function (editor, imageUploadTimerState) { |
||
3542 | return function () { |
||
3543 | var img = getSelectedImage(editor), originalSize = ImageSize$1.getNaturalImageSize(img); |
||
3544 | var handleDialogBlob = function (blob) { |
||
3545 | return new global$3(function (resolve) { |
||
3546 | BlobConversions.blobToImage(blob).then(function (newImage) { |
||
3547 | var newSize = ImageSize$1.getNaturalImageSize(newImage); |
||
3548 | if (originalSize.w !== newSize.w || originalSize.h !== newSize.h) { |
||
3549 | if (ImageSize$1.getImageSize(img)) { |
||
3550 | ImageSize$1.setImageSize(img, newSize); |
||
3551 | } |
||
3552 | } |
||
3553 | URL$1.revokeObjectURL(newImage.src); |
||
3554 | resolve(blob); |
||
3555 | }); |
||
3556 | }); |
||
3557 | }; |
||
3558 | var openDialog = function (editor, imageResult) { |
||
3559 | return Dialog.edit(editor, imageResult).then(handleDialogBlob).then(ResultConversions.blobToImageResult).then(function (imageResult) { |
||
3560 | return updateSelectedImage(editor, imageResult, true, imageUploadTimerState); |
||
3561 | }, function () { |
||
3562 | }); |
||
3563 | }; |
||
3564 | findSelectedBlob(editor).then(ResultConversions.blobToImageResult).then(curry(openDialog, editor), function (error) { |
||
3565 | displayError(editor, error); |
||
3566 | }); |
||
3567 | }; |
||
3568 | }; |
||
3569 | var Actions = { |
||
3570 | rotate: rotate$2, |
||
3571 | flip: flip$2, |
||
3572 | editImageDialog: editImageDialog, |
||
3573 | isEditableImage: isEditableImage, |
||
3574 | cancelTimedUpload: cancelTimedUpload |
||
3575 | }; |
||
3576 | |||
3577 | var register = function (editor, imageUploadTimerState) { |
||
3578 | global$1.each({ |
||
3579 | mceImageRotateLeft: Actions.rotate(editor, imageUploadTimerState, -90), |
||
3580 | mceImageRotateRight: Actions.rotate(editor, imageUploadTimerState, 90), |
||
3581 | mceImageFlipVertical: Actions.flip(editor, imageUploadTimerState, 'v'), |
||
3582 | mceImageFlipHorizontal: Actions.flip(editor, imageUploadTimerState, 'h'), |
||
3583 | mceEditImage: Actions.editImageDialog(editor, imageUploadTimerState) |
||
3584 | }, function (fn, cmd) { |
||
3585 | editor.addCommand(cmd, fn); |
||
3586 | }); |
||
3587 | }; |
||
3588 | var Commands = { register: register }; |
||
3589 | |||
3590 | var setup = function (editor, imageUploadTimerState, lastSelectedImageState) { |
||
3591 | editor.on('NodeChange', function (e) { |
||
3592 | var lastSelectedImage = lastSelectedImageState.get(); |
||
3593 | if (lastSelectedImage && lastSelectedImage.src !== e.element.src) { |
||
3594 | Actions.cancelTimedUpload(imageUploadTimerState); |
||
3595 | editor.editorUpload.uploadImagesAuto(); |
||
3596 | lastSelectedImageState.set(null); |
||
3597 | } |
||
3598 | if (Actions.isEditableImage(editor, e.element)) { |
||
3599 | lastSelectedImageState.set(e.element); |
||
3600 | } |
||
3601 | }); |
||
3602 | }; |
||
3603 | var UploadSelectedImage = { setup: setup }; |
||
3604 | |||
3605 | var register$1 = function (editor) { |
||
3606 | editor.addButton('rotateleft', { |
||
3607 | title: 'Rotate counterclockwise', |
||
3608 | cmd: 'mceImageRotateLeft' |
||
3609 | }); |
||
3610 | editor.addButton('rotateright', { |
||
3611 | title: 'Rotate clockwise', |
||
3612 | cmd: 'mceImageRotateRight' |
||
3613 | }); |
||
3614 | editor.addButton('flipv', { |
||
3615 | title: 'Flip vertically', |
||
3616 | cmd: 'mceImageFlipVertical' |
||
3617 | }); |
||
3618 | editor.addButton('fliph', { |
||
3619 | title: 'Flip horizontally', |
||
3620 | cmd: 'mceImageFlipHorizontal' |
||
3621 | }); |
||
3622 | editor.addButton('editimage', { |
||
3623 | title: 'Edit image', |
||
3624 | cmd: 'mceEditImage' |
||
3625 | }); |
||
3626 | editor.addButton('imageoptions', { |
||
3627 | title: 'Image options', |
||
3628 | icon: 'options', |
||
3629 | cmd: 'mceImage' |
||
3630 | }); |
||
3631 | }; |
||
3632 | var Buttons = { register: register$1 }; |
||
3633 | |||
3634 | var register$2 = function (editor) { |
||
3635 | editor.addContextToolbar(curry(Actions.isEditableImage, editor), getToolbarItems(editor)); |
||
3636 | }; |
||
3637 | var ContextToolbar = { register: register$2 }; |
||
3638 | |||
3639 | global.add('imagetools', function (editor) { |
||
3640 | var imageUploadTimerState = Cell(0); |
||
3641 | var lastSelectedImageState = Cell(null); |
||
3642 | Commands.register(editor, imageUploadTimerState); |
||
3643 | Buttons.register(editor); |
||
3644 | ContextToolbar.register(editor); |
||
3645 | UploadSelectedImage.setup(editor, imageUploadTimerState, lastSelectedImageState); |
||
3646 | }); |
||
3647 | function Plugin () { |
||
3648 | } |
||
3649 | |||
3650 | return Plugin; |
||
3651 | |||
3652 | }()); |
||
3653 | })(); |
||
3654 |