diff --git a/mig/assets/css/V3/jquery.managers.css b/mig/assets/css/V3/jquery.managers.css index 8f1302a9a..51b8afb6d 100644 --- a/mig/assets/css/V3/jquery.managers.css +++ b/mig/assets/css/V3/jquery.managers.css @@ -4,7 +4,7 @@ # --- BEGIN_HEADER --- # # jquery.managers - style overrides for multiple pages -# Copyright (C) 2003-2016 The MiG Project lead by Brian Vinter +# Copyright (C) 2003-2025 The MiG Project by the Science HPC Center at UCPH # # This file is part of MiG. # @@ -157,188 +157,6 @@ tbody tr td div.sortkey { display: none; } overflow: scroll; height: 500px; } -.fm_previews { - float: right; - width: 100%; - height: 0px; - background-color: #FFF; - visibility: hidden; -} -.fm_preview_caman { - float: right; - border: 0px; - width: 0px; - height: 0px; - background-color: #FFF; - visibility: hidden; -} -.fm_preview_paraview { - float: right; - border: 0px; - width: 0px; - height: 0px; - background-color: #FFF; - visibility: hidden; -} - -.fm_preview_menubar { - float: left; - border: 0px; - width: 20px; - height: 100%; - background-color: #EEE; -} -.fm_preview_menubar_entry { - border: 0px; - width: 19px; - margin-top: 1px; - margin-left: 1px; -} -.fm_preview_left_tile { - float: left; - border: 0px; - width: 0px; - height: 100%; - background-color: #FFF; - overflow-x: hidden; - overflow-y: auto; -} -.fm_preview_center_tile { - float: left; - border: 0px; - padding: 0px; - width: 0px; - height: 100%; - background-color: #FFF; - overflow-x: hidden; - overflow-y: hidden; -} -.fm_preview_right_tile { - float: left; - border: 0px; - width: 0px; - height: 100%; - background-color: #FFF; - overflow-x: hidden; - overflow-y: auto; -} -#fm_preview_left_tile_histogram { - display: block; - margin-top: 1%; - margin-left: 5%; - border: 0; - width : 80%; - height : 0px; - background-color: #FFF; -} -#fm_preview_left_tile_histogram_actions { - display: block; - margin-left: 5%; - border: 0; - width : 80%; - background-color: #FFF; -} -#fm_preview_left_output { - margin-left: 5%; - margin-right: 5%; - background-color: #FFF; -} -#fm_preview_right_output { - margin-left: 5%; - margin-right: 5%; - background-color: #FFF; -} -#fm_preview_left_tile .noUi-target { - border-radius: 4px; - border: 1px solid #D3D3D3; - box-shadow: inset 0 1px 1px #F0F0F0, 0 3px 6px -5px #BBB; -} -#fm_preview_left_tile .noUi-horizontal { - height: 8px !important; -} -#fm_preview_left_tile .noUi-horizontal .noUi-handle { - width: 6px; - height: 12px; - left: -3px; - top: -3px; -} -#fm_preview_left_tile .noUi-handle { - border: 1px solid #D9D9D9; - border-radius: 3px; - background: #FFF; - cursor: default; - box-shadow: inset 0 0 1px #FFF, - inset 0 1px 7px #EBEBEB, - 0 3px 6px -3px #BBB; -} -#fm_preview_left_tile .noUi-handle:before, -#fm_preview_left_tile .noUi-handle:after { - content: ""; - display: block; - position: absolute; - height: 0px; - width: 0px; - background: #E8E7E6; - left: -3px; - top: -3px; -} -#fm_preview_left_tile .noUi-handle:after { - left: 17px; -} -#fm_preview_left_tile .noUi-handle { -} -#fm_preview_histogram_min_max_slider .noUi-origin { -} -#fm_preview_histogram_min_max_slider .noUi-handle { -} -#fm_preview_histogram_min_max_slider .noUi-handle-lower { -} -#fm_preview_histogram_min_max_slider .noUi-handle-upper { -} -#fm_preview_left_tile .noUi-base { - background: lightgrey; -} -#fm_preview_histogram_min_max_slider .noUi-connect { - background: black; -} -#fm_preview_histogram_min_max_slider .noUi-background{ - background: lightgrey; -} -#fm_preview_histogram_min_max_slider .noUi-state-tap { -} -#fm_preview_histogram_min_max_slider .fm_preview_histogram_min_max_slider_tooltip { - display: block; - position: absolute; - border: 0px solid #D9D9D9; - font-size: 12px; - top: -5px; - padding: 0px; - left: -13px; - text-align: center; - width: 30px; -} -.fm_preview_min_max_slider_tooltip_org { - display: block; - position: absolute; - border: 1px solid #D9D9D9; - font: 400 12px/12px Arial; - border-radius: 3px; - background: #fff; - top: -43px; - padding: 5px; - left: -9px; - text-align: center; - width: 50px; -} -/* hide paraview SVG bar which only shows up on IE and covers refresh button */ -.fm_previews .pipelineSVG svg rect { - display: none; -} -/* avoid waiting banner from flying around */ -.fm_previews .app-wait-start-page { - position: absolute; -} - .fm_metaio_list ul.edit { list-style-image: url(/images/icons/page_white_edit.png); } diff --git a/mig/cgi-bin/imagepreview.py b/mig/cgi-bin/imagepreview.py deleted file mode 100755 index 6b2814ed9..000000000 --- a/mig/cgi-bin/imagepreview.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# --- BEGIN_HEADER --- -# -# imagepreview - front end to file metadata I/O -# Copyright (C) 2003-2015 The MiG Project lead by Brian Vinter -# -# This file is part of MiG. -# -# MiG is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# MiG is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# -- END_HEADER --- -# - -"""Image preview helper page""" -from __future__ import absolute_import - -import cgi -import cgitb -# cgitb.enable() - -from mig.shared.functionality.imagepreview import main -from mig.shared.cgiscriptstub import run_cgi_script - -run_cgi_script(main) diff --git a/mig/images/css/jquery.managers.css b/mig/images/css/jquery.managers.css index 5813f875e..bf3020661 100644 --- a/mig/images/css/jquery.managers.css +++ b/mig/images/css/jquery.managers.css @@ -4,7 +4,7 @@ # --- BEGIN_HEADER --- # # jquery.managers - style overrides for multiple pages -# Copyright (C) 2003-2016 The MiG Project lead by Brian Vinter +# Copyright (C) 2003-2025 The MiG Project by the Science HPC Center at UCPH # # This file is part of MiG. # @@ -161,188 +161,6 @@ tbody tr td div.sortkey { display: none; } overflow: scroll; height: 500px; } -.fm_previews { - float: right; - width: 100%; - height: 0px; - background-color: #FFF; - visibility: hidden; -} -.fm_preview_caman { - float: right; - border: 0px; - width: 0px; - height: 0px; - background-color: #FFF; - visibility: hidden; -} -.fm_preview_paraview { - float: right; - border: 0px; - width: 0px; - height: 0px; - background-color: #FFF; - visibility: hidden; -} - -.fm_preview_menubar { - float: left; - border: 0px; - width: 20px; - height: 100%; - background-color: #EEE; -} -.fm_preview_menubar_entry { - border: 0px; - width: 19px; - margin-top: 1px; - margin-left: 1px; -} -.fm_preview_left_tile { - float: left; - border: 0px; - width: 0px; - height: 100%; - background-color: #FFF; - overflow-x: hidden; - overflow-y: auto; -} -.fm_preview_center_tile { - float: left; - border: 0px; - padding: 0px; - width: 0px; - height: 100%; - background-color: #FFF; - overflow-x: hidden; - overflow-y: hidden; -} -.fm_preview_right_tile { - float: left; - border: 0px; - width: 0px; - height: 100%; - background-color: #FFF; - overflow-x: hidden; - overflow-y: auto; -} -#fm_preview_left_tile_histogram { - display: block; - margin-top: 1%; - margin-left: 5%; - border: 0; - width : 80%; - height : 0px; - background-color: #FFF; -} -#fm_preview_left_tile_histogram_actions { - display: block; - margin-left: 5%; - border: 0; - width : 80%; - background-color: #FFF; -} -#fm_preview_left_output { - margin-left: 5%; - margin-right: 5%; - background-color: #FFF; -} -#fm_preview_right_output { - margin-left: 5%; - margin-right: 5%; - background-color: #FFF; -} -#fm_preview_left_tile .noUi-target { - border-radius: 4px; - border: 1px solid #D3D3D3; - box-shadow: inset 0 1px 1px #F0F0F0, 0 3px 6px -5px #BBB; -} -#fm_preview_left_tile .noUi-horizontal { - height: 8px !important; -} -#fm_preview_left_tile .noUi-horizontal .noUi-handle { - width: 6px; - height: 12px; - left: -3px; - top: -3px; -} -#fm_preview_left_tile .noUi-handle { - border: 1px solid #D9D9D9; - border-radius: 3px; - background: #FFF; - cursor: default; - box-shadow: inset 0 0 1px #FFF, - inset 0 1px 7px #EBEBEB, - 0 3px 6px -3px #BBB; -} -#fm_preview_left_tile .noUi-handle:before, -#fm_preview_left_tile .noUi-handle:after { - content: ""; - display: block; - position: absolute; - height: 0px; - width: 0px; - background: #E8E7E6; - left: -3px; - top: -3px; -} -#fm_preview_left_tile .noUi-handle:after { - left: 17px; -} -#fm_preview_left_tile .noUi-handle { -} -#fm_preview_histogram_min_max_slider .noUi-origin { -} -#fm_preview_histogram_min_max_slider .noUi-handle { -} -#fm_preview_histogram_min_max_slider .noUi-handle-lower { -} -#fm_preview_histogram_min_max_slider .noUi-handle-upper { -} -#fm_preview_left_tile .noUi-base { - background: lightgrey; -} -#fm_preview_histogram_min_max_slider .noUi-connect { - background: black; -} -#fm_preview_histogram_min_max_slider .noUi-background{ - background: lightgrey; -} -#fm_preview_histogram_min_max_slider .noUi-state-tap { -} -#fm_preview_histogram_min_max_slider .fm_preview_histogram_min_max_slider_tooltip { - display: block; - position: absolute; - border: 0px solid #D9D9D9; - font-size: 12px; - top: -5px; - padding: 0px; - left: -13px; - text-align: center; - width: 30px; -} -.fm_preview_min_max_slider_tooltip_org { - display: block; - position: absolute; - border: 1px solid #D9D9D9; - font: 400 12px/12px Arial; - border-radius: 3px; - background: #fff; - top: -43px; - padding: 5px; - left: -9px; - text-align: center; - width: 50px; -} -/* hide paraview SVG bar which only shows up on IE and covers refresh button */ -.fm_previews .pipelineSVG svg rect { - display: none; -} -/* avoid waiting banner from flying around */ -.fm_previews .app-wait-start-page { - position: absolute; -} - .fm_metaio_list ul.edit { list-style-image: url(/images/icons/page_white_edit.png); } diff --git a/mig/images/js/jquery.filemanager.js b/mig/images/js/jquery.filemanager.js index 4cf082805..3d86bb0ea 100644 --- a/mig/images/js/jquery.filemanager.js +++ b/mig/images/js/jquery.filemanager.js @@ -577,9 +577,6 @@ if (jQuery) (function($){ buttonSpacing: buttonSpacing } }; - if (options['imagesettings']) { - layout = preview.update_fm_layout(layout); - } return layout; } @@ -611,14 +608,6 @@ if (jQuery) (function($){ return layout; } - function clickEvent(el) { - if (!options['imagesettings']) { - console.debug('clickEvent: imagesettings is false'); - } else { - preview.open($(el).attr(pathAttribute)); - } - } - function doubleClickEvent(el) { if (clickaction !== undefined) { clickaction(el); @@ -1691,11 +1680,6 @@ if (jQuery) (function($){ }); $("#import_freeze_dialog").dialog('open'); $("#import_freeze_form input[name='freeze_id']").focus(); - }, - imagesettings: function(action, el, pos) { - var rel_path = $(el).attr(pathAttribute); - var open_dialog = mig_imagesettings_init("imagesettings_dialog", rel_path, options); - open_dialog("Image Settings"); } }; @@ -1722,7 +1706,6 @@ if (jQuery) (function($){ refreshLayoutOnInit: false, enableSubmit: true, selectOnly: false, - imagesettings: false, enableGDP: false, maxStreamSize: 64*1024*1024 }; @@ -1739,40 +1722,13 @@ if (jQuery) (function($){ } */ }); - // Initiate preview - - var preview = null; - if (options['imagesettings']) { - preview = new Preview( - get_fm_layout, - options, - enable_debug); - } - - $.fn.refresh_fm_layout = refresh_fm_layout; - // Define window behavior $(window).on("resize", function() { - if (options['imagesettings']) { - preview.set_visibility('hidden'); - } console.debug("refresh layout on resize"); $.fn.refresh_fm_layout(); }); - $(window).on("debouncedresize", function() { - if (options['imagesettings']) { - preview.refresh(); - } - - }); - - $(window).on('beforeunload', function(){ - if (options['imagesettings']) { - preview.close(); - } - }); // reestablish defaults for undefined actions: $.each(callbacks, function(name, fct) { @@ -2263,8 +2219,6 @@ if (jQuery) (function($){ "sep2": "---------", "rename": {name: "Rename", icon: "rename"}, "sep3": "---------", - "imagesettings": {name: "Image Settings", icon: "edit"}, - "sep4": "---------", "sharelinks": {"name": "Share Link", icon: "sharelink", "items": {"createsharelink": {name: "Create", icon: "createsharelink"}, "importsharelink": {name: "Import", icon: "importsharelink"} @@ -2349,10 +2303,6 @@ if (jQuery) (function($){ } } }; - if (!options["imagesettings"]) { - delete directory_menu["imagesettings"]; - delete directory_menu["sep4"]; - } if (!options["enableSubmit"]) { delete file_menu["submit-sep"]; delete file_menu["submit"]; @@ -2456,13 +2406,6 @@ if (jQuery) (function($){ function bindHandlers(folder_pane) { bindContextMenus(); - console.debug("add click handler"); - $.fn.fmSelect("").on("click", - "tr.file", - function(event) { - clickEvent(this); - }); - console.debug("add dblclick handler"); //$.fn.fmSelect("").off("dblclick", "tr.file, tr.directory"); $.fn.fmSelect("").on("dblclick", @@ -2606,15 +2549,6 @@ if (jQuery) (function($){ bindHandlers(folder_pane); showBranch(folder_pane, encodeURI(options.root)); - - /* - * Bind preview buttons - */ - - if (options['imagesettings']) { - preview.bind_buttons(); - } - /** * Bind handlers for forms. This is ridiculous and tedious repetitive code. @@ -2913,7 +2847,6 @@ function mig_filechooser_init(name, callback, files_only, start_path) { datatransfersbutton: false, datasafetypopup: false, refreshLayoutOnInit: true, - imagesettings: false, selectOnly: true }, // doubleclick callback action @@ -3442,512 +3375,3 @@ function mig_fancyuploadchunked_init(name, options, callback) { return do_d; } - -/* Image settings dialog */ - -function mig_imagesettings_init(name, path, options) { - var edit_form_values = { - extension: '', - settings_status: '', - settings_recursive: '', - image_type: '', - data_type: '', - volume_slice_filepattern: '', - offset: 0, - x_dimension: 0, - y_dimension: 0, - z_dimension: 0, - preview_cutoff_min: 0.0, - preview_cutoff_max: 0.0, - }; - - init_html_and_handlers(); - - $("#" + name).dialog( - // see http://jqueryui.com/docs/dialog/ for options - { - autoOpen: false, - modal: true, - width: 480, - position: { my: "top", at: "top+100px", of: window}, - buttons: dialog_list_buttons() - }); - - function dialog_list_buttons() { - return { - 'New': function() { - edit(null); - }, - 'Clear': function() { - remove_all(); - }, - 'Refresh': function() { - show_list(); - }, - 'Close': function() { - $("#" + name).dialog("close"); - } - }; - } - - function dialog_new_buttons() { - return { - 'Create': function() { - $("#imagesettings_form").submit(); - }, - 'Cancel': function() { - show_list(); - }, - 'Close': function() { - $("#" + name).dialog("close"); - } - }; - } - - function dialog_edit_buttons() { - return { - 'Update': function() { - $("#imagesettings_form").submit(); - }, - 'Remove': function() { - remove(); - }, - 'Back': function() { - show_list(); - }, - 'Close': function() { - $("#" + name).dialog("close"); - } - }; - } - - // Initializes html and handlers - - function init_html_and_handlers() { - $("#imagesettings_edit").hide(); - $("#imagesettings_edit_tabs").hide(); - - // Handle image settings file form submit - - $("#imagesettings_form").ajaxForm({ - target: '#imagesettings_output', dataType: 'json', - success: function(responseObject, statusText) { - var msg; - var errors = $(this).renderError(responseObject); - var warnings = $(this).renderWarning(responseObject); - if (errors.length > 0) { - msg = errors; - console.debug(errors); - } else if (warnings.length > 0) { - msg = warnings; - console.debug(warnings); - } else { - msg = 'Image file settings updated'; - } - show_list(msg); - }, - error: function(jqXHR, textStatus, errorThrown) { - console.error("imagesettings_form error: "+ textStatus); - console.debug("imagesettings_form error: "+ errorThrown); - } - }); - - // Changes based on image_type - - $("#imagesettings_form select[name='image_type']").on('change', function() { - var image_type_value = $("#imagesettings_form select[name='image_type']").val(); - var data_type_value = $("#imagesettings_form select[name='data_type']").val(); - - // Set data_type based on image_type - - if (image_type_value === 'tiff') { - data_type_value = 'uint16'; - } - else { - data_type_value = edit_form_values['data_type']; - } - $("#imagesettings_form select[name='data_type']").val(data_type_value).prop('selected', true); - - // Only display options for raw data if 'raw' is selected' - - if (image_type_value === 'raw') { - $("#imagesettings_edit_image_type_raw").show({duration: options.expandSpeed, - easing: options.expandEasing }); - } - else { - $("#imagesettings_edit_image_type_raw").hide({duration: options.expandSpeed, - easing: options.expandEasing }); - } - }); - - // Change Sub-folder checkbox value when checked/unchecked - - $("#imagesettings_form input[name='settings_recursive']").on('change', function() { - if ($("#imagesettings_form input[name='settings_recursive']").prop("checked")) { - $("#imagesettings_form input[name='settings_recursive']").val('True'); - } - else { - $("#imagesettings_form input[name='settings_recursive']").val('False'); - } - }); - } - - function show_list(output_msg) { - - // Generate image extension list - var html_out; - - if (output_msg === undefined) { - html_out = ''; - } - else { - html_out = '

' + output_msg + '

'; - } - $("#imagesettings_output").html(html_out); - $("#imagesettings_list").hide(({duration: options.expandSpeed, - easing: options.expandEasing })); - $("#imagesettings_edit_tabs").hide(({duration: options.expandSpeed, - easing: options.expandEasing })); - - // Retrieve image settings list - - $.ajax({ - url: 'imagepreview.py', - data: { path: path, - output_format: 'json' , - action: 'list_settings'}, - type: "GET", - dataType: "json", - cache: false, - success: function (jsonRes) { - var errors = $(this).renderError(jsonRes); - var warnings = $(this).renderWarning(jsonRes); - if (errors.length > 0) { - console.debug(errors); - } else if (warnings.length > 0) { - console.debug(warnings); - } - - var i; - var extension_list = []; - var image_settings_status_list = []; - var image_settings_progress_list = []; - var image_count_list = []; - var volume_settings_status_list = []; - var volume_settings_progress_list = []; - var volume_count_list = []; - - // Generate extension, status, progress and count lists for each entry - - for (i = 0; i < jsonRes.length; i++) { - if (jsonRes[i].object_type === 'image_settings_list') { - extension_list = extension_list.concat(jsonRes[i].extension_list); - image_settings_status_list = image_settings_status_list.concat(jsonRes[i].image_settings_status_list); - image_settings_progress_list = image_settings_progress_list.concat(jsonRes[i].image_settings_progress_list); - image_count_list = image_count_list.concat(jsonRes[i].image_count_list); - volume_settings_status_list = image_settings_status_list.concat(jsonRes[i].image_settings_status_list); - volume_settings_progress_list = volume_settings_progress_list.concat(jsonRes[i].volume_settings_progress_list); - volume_count_list = volume_count_list.concat(jsonRes[i].volume_count_list); - } - } - - // Generate html for each entry - - var html_out = '

Image file extensions:

'; - if (image_settings_status_list.length === 0) { - html_out += '

-- No folder image settings configured --

'; - } - - for (i = 0; i < image_settings_status_list.length; i++) { - if (image_settings_status_list[i].toLowerCase() === 'ready' || - image_settings_status_list[i].toLowerCase() === 'failed') { - html_out += ''; - } - $("#imagesettings_list").html(html_out); - - // Attach 'edit' handler to each list element - - $("#imagesettings_list ul.edit li").click(function() { - edit($(this).attr('extension')); - }); - - // Show list - - $("#imagesettings_list").show(({duration: options.expandSpeed, - easing: options.expandEasing})); - - // Set dialog buttons - - $("#" + name).dialog('option', 'buttons', dialog_list_buttons()); - }, - error: function(jqXHR, textStatus, errorThrown) { - console.error("image settings -> show_list error: " + textStatus); - console.debug("image settings -> show_list error: " + errorThrown); - /* TODO: add $.fn.handleAjaxError fallback using #imagesettings_output here? */ - } - }); - } - - // Removes all element from list - - function remove_all() { - var call_args = { path: path, - output_format: 'json' , - action: 'remove_setting'}; - call_args[csrf_field] = csrf_map['imagepreview']; - $.ajax({ - url: 'imagepreview.py', - data: call_args, - type: "POST", - dataType: "json", - cache: false, - success: function (jsonRes) { - console.debug('imagesettings edit jsonRes.length: ' + jsonRes.length); - var i; - var errors = $(this).renderError(jsonRes); - var warnings = $(this).renderWarning(jsonRes); - var msg = ''; - - if (errors.length > 0) { - msg = errors; - console.debug(msg); - } else if (warnings.length > 0) { - msg = warnings; - console.debug(msg); - } else { - msg = 'Image Settings Cleared'; - } - show_list(msg); - }, - error: function(jqXHR, textStatus, errorThrown) { - console.error("image settings -> remove_all error: " + textStatus); - console.debug("image settings -> remove_all error: " + errorThrown); - /* TODO: add $.fn.handleAjaxError fallback using #imagesettings_output here? */ - } - }); - } - - // Remove an element from list - - function remove() { - var extension = $("#imagesettings_form input[name='extension']").val(); - var call_args = { path: path, - output_format: 'json' , - action: 'remove_setting', - extension: extension}; - call_args[csrf_field] = csrf_map['imagepreview']; - $.ajax({ - url: 'imagepreview.py', - data: call_args, - type: "POST", - dataType: "json", - cache: false, - success: function (jsonRes) { - var i; - var errors = $(this).renderError(jsonRes); - var warnings = $(this).renderWarning(jsonRes); - var msg = ''; - - if (errors.length > 0) { - msg = errors; - console.debug(msg); - } else if (warnings.length > 0) { - msg = warnings; - console.debug(msg); - } else { - msg = "Image setting for: '" + extension + "'' removed"; - } - show_list(msg); - }, - error: function(jqXHR, textStatus, errorThrown) { - console.error("image settings -> remove error: " + textStatus); - console.debug("image settings -> remove error: " + errorThrown); - /* TODO: add $.fn.handleAjaxError fallback using #imagesettings_output here? */ - } - }); - } - - function hide_edit_tabs() { - return; - } - - function show_edit_tabs() { - return; - } - - // Prepare edit image setting data - - function edit(extension) { - if (extension === null) { - edit_form_values['extension'] = ''; - edit_form_values['settings_status'] = 'Pending'; - edit_form_values['settings_recursive'] = 'False'; - edit_form_values['image_type'] = 'raw'; - edit_form_values['data_type'] = 'float32'; - edit_form_values['volume_slice_filepattern'] = ''; - edit_form_values['offset'] = 0; - edit_form_values['x_dimension'] = 0; - edit_form_values['y_dimension'] = 0; - edit_form_values['z_dimension'] = 0; - edit_form_values['preview_cutoff_min'] = 0; - edit_form_values['preview_cutoff_max'] = 0; - do_edit(); - } else { - $.ajax({ - url: 'imagepreview.py', - data: { extension: extension, - path: path, - output_format: 'json', - action: 'get_setting'}, - type: "GET", - dataType: "json", - cache: false, - success:function (jsonRes) { - console.debug('imagesettings edit jsonRes.length: ' + jsonRes.length); - var i; - var errors = $(this).renderError(jsonRes); - var warnings = $(this).renderWarning(jsonRes); - - if (errors.length > 0) { - $("#imagesettings_output").html(errors); - console.debug(errors); - } else if (warnings.length > 0) { - $("#imagesettings_output").html(warnings); - console.debug(warnings); - } - - for (i = 0; i < jsonRes.length; i++) { - if (jsonRes[i].object_type === 'image_setting') { - edit_form_values['extension'] = jsonRes[i]['extension']; - edit_form_values['settings_recursive'] = jsonRes[i]['settings_recursive']; - edit_form_values['image_type'] = jsonRes[i]['image_type']; - edit_form_values['data_type'] = jsonRes[i]['data_type']; - edit_form_values['volume_slice_filepattern'] = jsonRes[i]['volume_slice_filepattern']; - edit_form_values['offset'] = jsonRes[i]['offset']; - edit_form_values['x_dimension'] = jsonRes[i]['x_dimension']; - edit_form_values['y_dimension'] = jsonRes[i]['y_dimension']; - edit_form_values['z_dimension'] = jsonRes[i]['z_dimension']; - edit_form_values['preview_cutoff_min'] = jsonRes[i]['preview_cutoff_min']; - edit_form_values['preview_cutoff_max'] = jsonRes[i]['preview_cutoff_max']; - } - } - do_edit(); - }, - error: function(jqXHR, textStatus, errorThrown) { - console.error("image settings edit-> remove error: " + textStatus); - console.debug("image settings edit-> remove error: " + errorThrown); - /* TODO: add $.fn.handleAjaxError fallback using #imagesettings_output here? */ - } - }); - } - } - - // Handle edit image setting - - function do_edit() { - $("#imagesettings_output").html(''); - - $("#imagesettings_list").hide(({duration: options.expandSpeed, - easing: options.expandEasing })); - $("#imagesettings_edit_file_tab").hide(({duration: options.expandSpeed, - easing: options.expandEasing })); - $("#imagesettings_edit_volume_tab").hide({duration: options.expandSpeed, - easing: options.expandEasing }); - - // Fill edit html form - - $("#imagesettings_form input[name='path']").val(path); - $("#imagesettings_form input[name='action']").val('create_setting'); - $("#imagesettings_form input[name='settings_status']").val(edit_form_values['image_settings_status']); - $("#imagesettings_form input[name='extension']").val(edit_form_values['extension']); - if (edit_form_values['extension'] !== '') { - $("#imagesettings_form input[name='extension']").attr("readonly", true); - } - else { - $("#imagesettings_form input[name='extension']").attr("readonly", false); - } - if (edit_form_values['settings_recursive'] === 'True') { - $("#imagesettings_form input[name='settings_recursive']").prop('checked', true).change(); - } - else { - $("#imagesettings_form input[name='settings_recursive']").prop('checked', false).change(); - } - $("#imagesettings_form select[name='image_type']").val(edit_form_values['image_type']).prop('selected', true).change(); - if (edit_form_values['data_type'] !== 'None') { - $("#imagesettings_form select[name='data_type']").val(edit_form_values['data_type']).prop('selected', true); - } - $("#imagesettings_form input[name='volume_slice_filepattern']").val(edit_form_values['volume_slice_filepattern']); - $("#imagesettings_form input[name='offset']").val(edit_form_values['offset']); - $("#imagesettings_form input[name='x_dimension']").val(edit_form_values['x_dimension']); - $("#imagesettings_form input[name='y_dimension']").val(edit_form_values['y_dimension']); - $("#imagesettings_form input[name='z_dimension']").val(edit_form_values['z_dimension']); - $("#imagesettings_form input[name='preview_cutoff_min']").val(edit_form_values['preview_cutoff_min']); - $("#imagesettings_form input[name='preview_cutoff_max']").val(edit_form_values['preview_cutoff_max']); - - // Show edit file html form and tab - - $("#imagesettings_edit_file_tab").show({duration: options.expandSpeed, - easing: options.expandEasing}); - - $("#imagesettings_edit_tabs").show({duration: options.expandSpeed, - easing: options.expandEasing }); - - - $('#imagesettings_edit_tabs').tabs({ active: 0 }); - - // Set dialog buttons - - if (edit_form_values['extension'] === '') { - $("#" + name).dialog('option', 'buttons', dialog_new_buttons()); - } - else { - $("#" + name).dialog('option', 'buttons', dialog_edit_buttons()); - } - } - - // Initial function used for when opening dialog - - var do_d = function(text) { - - console.debug('mig_imagesettings dialog: ' + name + ', ' + text + ', ' + path); - $("#" + name).dialog("open"); - - show_list(); - }; - - return do_d; -} diff --git a/mig/images/js/preview-caman.js b/mig/images/js/preview-caman.js deleted file mode 100644 index 590514bdc..000000000 --- a/mig/images/js/preview-caman.js +++ /dev/null @@ -1,527 +0,0 @@ -/* - -# -# --- BEGIN_HEADER --- -# -# caman - javascript based image Caman library -# Copyright (C) 2003-2016 The MiG Project lead by Brian Vinter -# -# This file is part of MiG. -# -# MiG is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public Licethnse as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# MiG is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# -- END_HEADER --- -# - -*/ - -/* - -This module is based on the CamanJS module: http://camanjs.com/ - -# Copyright notice follows here: - -Copyright (c) 2010, Ryan LeFevre -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Ryan LeFevre nor the names of its contributors may be - used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - - -PreviewCaman = function (max_decimals, debug) { - console.debug('PreviewCaman: constructor -> max_decimals: ' + max_decimals); - console.debug('PreviewCaman: constructor -> debug: ' + debug); - this.settings = { - debug: debug, - max_decimals: max_decimals, - }; - - this.image = this.init_image(); - this.histogram = this.init_histogram(); - this.init_min_max_slider(); -} - -PreviewCaman.prototype.init_caman_struct = function() { - - return {div_id: null, - canvas_id: null, - canvas_width: 0, - canvas_height: 0, - image_width: 0, - image_height: 0, - image_offset_x: 0, - image_offset_y: 0, - image_url: null, - image_obj: new Image() - }; -} - -PreviewCaman.prototype.init_image = function() { - var result = this.init_caman_struct(); - result.div_id = "#fm_preview_center_tile"; - result.canvas_id = "#fm_preview_image"; - - return result; -} - -PreviewCaman.prototype.init_histogram = function() { - var result = this.init_caman_struct(); - result.div_id = "#fm_preview_left_tile_histogram"; - result.canvas_id = "#fm_preview_histogram_image"; - return result; -} - -PreviewCaman.prototype.clear_canvas = function(canvas) { - var context = canvas.getContext('2d'); - - // Clear rect and ensure white background - - context.clearRect(0, 0, canvas.width, canvas.height); - context.fillStyle = "#FFFFFF"; - context.fillRect(0, 0, canvas.width, canvas.height); - -} - -PreviewCaman.prototype.set_image_url = function(image_url) { - this.image.image_url = image_url; -} - -PreviewCaman.prototype.set_histogram_data = function(data) { - this.histogram.data = data; -} - - -PreviewCaman.prototype.load_image = function(image_url) { - this.image_dim_update(); - if (image_url !== undefined) { - this.image.image_url = image_url; - } - this.image_data_load(this.image); -} - -PreviewCaman.prototype.dim_update = function() { - this.image_dim_update(); - this.histogram_dim_update(); -} - -PreviewCaman.prototype.image_dim_update = function() { - var image_border = 1; - var canvas = $(this.image.canvas_id)[0]; - var context = canvas.getContext('2d'); - var width = $(this.image.div_id).width(); - var height = $(this.image.div_id).height(); - var image_size = width < height ? width : height; - var loaded_image_width = this.image.image_obj.width; - var loaded_image_height = this.image.image_obj.height; - var loaded_image_ratio = loaded_image_width/loaded_image_height; - - console.debug('html image width: ' + width); - console.debug('html image height: ' + height); - console.debug('html image_size: ' + image_size); - console.debug('loaded_image_width: ' + loaded_image_width); - console.debug('loaded_image_height: ' + loaded_image_height); - console.debug('loaded_image_ratio: ' + loaded_image_ratio); - context.canvas.width = width; - context.canvas.height = height; - - image_size -= Math.floor(image_size * (image_border/100.0)); - - this.image.canvas_width = width; - this.image.canvas_height = height; - - // Adjust for NON-Square images - - this.image.image_width = Math.floor(image_size * loaded_image_ratio); - this.image.image_height = image_size; - - if (this.image.image_width > width) { - this.image.image_width = width; - this.image.image_height = width / loaded_image_ratio; - } - if (this.image.image_height > height) { - this.image.image_width = height * loaded_image_ratio; - this.image.image_height = height; - } - - //this.image.image_offset_x = Math.floor((width - image_size)/2); - this.image.image_offset_x = Math.floor((width - this.image.image_width)/2); - this.image.image_offset_y = Math.floor((height - this.image.image_height)/2); - - console.debug("PreviewCaman image canvas id: " + this.image.div_id); - console.debug("PreviewCaman image canvas width: " + width); - console.debug("PreviewCaman image canvas height: " + height); - console.debug("PreviewCaman image_size: " + image_size); - console.debug("PreviewCaman image_width: " + this.image.image_width); - console.debug("PreviewCaman image_height: " + this.image.image_height); - console.debug("PreviewCaman x_offset: " + this.image.image_offset_x); - console.debug("PreviewCaman y_offset: " + this.image.image_offset_y); -} - -PreviewCaman.prototype.histogram_dim_update = function() { - var canvas = $(this.histogram.canvas_id)[0]; - var context = canvas.getContext('2d'); - var width = $(this.histogram.div_id).width(); - var height = width/3; - - - console.debug("PreviewCaman: update_histogram: width: " + width); - console.debug("PreviewCaman: update_histogram: height: " + height); - - context.canvas.width = width; - context.canvas.height = height; - - $(this.histogram.div_id).css("height", height); - this.histogram.image_width = context.canvas.width; - this.histogram.image_height = context.canvas.height; - this.histogram.image_offset_x = 0; - this.histogram.image_offset_y = 0; - - console.debug("PreviewCaman load histogram canvas id: " + this.histogram.canvas_id); - console.debug("PreviewCaman load histogram canvas: width: " + width); - console.debug("PreviewCaman load histogram canvas: height: " + height); - console.debug("PreviewCaman load histogram image_width: " + this.histogram.image_width); - console.debug("PreviewCaman load histogram image_height: " + this.histogram.image_height); - console.debug("PreviewCaman load histogram x_offset: " + this.histogram.image_offset_x); - console.debug("PreviewCaman load histogram y_offset: " + this.histogram.image_offset_y); -} - -PreviewCaman.prototype.load = function(image_url) { - // If we allready loaded image, then just refresh - // NOTE: Safari do not trigger onLoad if image_url - // is unchanged. - if (this.image.image_url === image_url) { - this.refresh(); - } - else { - this.load_image(image_url); - this.draw_histogram(); - } -} - -PreviewCaman.prototype.refresh = function(visible, callback) { - if (visible == true) { - this.draw_histogram(); - this.image_data_update(this.image, callback); - } -} - -PreviewCaman.prototype.image_data_update = function(caman_struct, callback) { - var _this = this; - var canvas = $(caman_struct.canvas_id)[0]; - var context = canvas.getContext('2d'); - - var min_value = $(this.min_slider_value_id).text(); - var max_value = $(this.max_slider_value_id).text(); - - // Update image dimensions - - this.image_dim_update(); - // PreviewCaman function calls are put in a queue and - // when .render() is called - - Caman(caman_struct.canvas_id, function() { - - // Clear rect and ensure white background - - _this.clear_canvas(canvas); - - // Draw image - - context.drawImage(caman_struct.image_obj, - caman_struct.image_offset_x, - caman_struct.image_offset_y, - caman_struct.image_width, - caman_struct.image_height); - - // Renew PreviewCaman canvas from drawn context - - this.replaceCanvas(canvas); - - // Issue a copy of loaded pixel data - - this.idmc_reset_original_pixeldata(); - - // Adjust min/max values - - this.idmc_set_min_max_pixel_values(min_value, max_value); - - // Render image - - this.render(); - - // Callback - - if (typeof callback === "function") { - callback(); - } - }); -} - -PreviewCaman.prototype.image_data_load = function(caman_struct) { - var caman_obj = this; - var image_obj = caman_struct.image_obj; - var image_url = caman_struct.image_url; - - console.debug("PreviewCaman: image_data_load -> loading: " + caman_struct.image_url); - - image_obj.onload = function(event) { - caman_obj.image_data_update(caman_struct); - }; - image_obj.src = image_url; -} - -PreviewCaman.prototype.update_preview_min_max_values = function() { - var tmp = this.settings; - var max_decimals = this.settings.max_decimals; - var slider_min_value = $("#fm_preview_histogram_min_slider_value").html(); - var slider_max_value = $("#fm_preview_histogram_max_slider_value").html(); - var cutoff_min_value = $("#fm_preview_left_output input[name='cutoff_min_value']").val(); - var current_min_value = $("#fm_preview_left_output input[name='current_min_value']").val(); - var current_max_value = $("#fm_preview_left_output input[name='current_max_value']").val(); - var scale_value = $("#fm_preview_left_output input[name='scale_value']").val(); - - var new_min_value; - var new_max_value; - - if (slider_min_value !== undefined && - slider_max_value !== undefined && - current_min_value !== undefined && - current_max_value !== undefined && - scale_value !== undefined) { - - slider_min_value = Number(slider_min_value); - slider_max_value = Number(slider_max_value); - cutoff_min_value = Number(cutoff_min_value); - current_min_value = Number(current_min_value); - current_max_value = Number(current_max_value); - scale_value = Number(scale_value); - - new_min_value = cutoff_min_value + (slider_min_value / scale_value); - new_max_value = cutoff_min_value + (slider_max_value / scale_value); - - $("#fm_preview_left_output input[name='current_min_value']").val(new_min_value); - $("#fm_preview_left_output input[name='current_max_value']").val(new_max_value); - $("#fm_preview_left_output_min_value_show").html("Min: " + Number(new_min_value).toExponential(max_decimals)); - $("#fm_preview_left_output_max_value_show").html("Max: " + Number(new_max_value).toExponential(max_decimals)); - $("#fm_preview_left_output_preview_image_scale_value_show").html("Slider Scale: " + Number(scale_value).toExponential(max_decimals)); - } -} - -PreviewCaman.prototype.init_min_max_slider = function() { - - // http://refreshless.com/nouislider/ - - var _this = this; - - _this.slider_id = "#fm_preview_histogram_min_max_slider"; - _this.min_slider_value_id = "#fm_preview_histogram_min_slider_value"; - _this.min_slider_value = 0; - - _this.max_slider_value_id = "#fm_preview_histogram_max_slider_value"; - _this.max_slider_value = 255; - - var min_slider_value_id = _this.min_slider_value_id; - var min_slider_value = _this.min_slider_value; - var max_slider_value_id = _this.max_slider_value_id; - var max_slider_value = _this.max_slider_value; - var image = _this.image; - - $(_this.slider_id).noUiSlider({ - start: [ min_slider_value, max_slider_value ], - connect: true, - step: 1, - range: { - 'min': min_slider_value, - 'max': max_slider_value, - }, - - // Full number format support. - - format: wNumb({ - mark: ',', - decimals: 0 - }), - }); - - // Setup min slider - - $(_this.slider_id).Link('lower').to('-inline-
', function ( value ) { - - // The tooltip HTML is 'this', so additional markup can be inserted here. - - $(this).html( - '
' + - '' + value + '' - ); - - _this.update_preview_min_max_values(); - }); - - // Setup max slider - - $(_this.slider_id).Link('upper').to('-inline-
', function ( value ) { - - // The tooltip HTML is 'this', so additional markup can be inserted here. - $(this).html( - '
' + - '' + value + '' - ); - - _this.update_preview_min_max_values(); - }); - - - // Setup slider change handler - - $(_this.slider_id).on('change', function() { - var min_value = $(min_slider_value_id).text(); - var max_value = $(max_slider_value_id).text(); - - var caman = Caman(image.canvas_id, function() { - this.idmc_set_min_max_pixel_values(min_value, max_value); - this.render(); - }); - }); -} - -// Reset sliders - -PreviewCaman.prototype.reset = function() { - var slider_id = this.slider_id; - var min_slider_value = this.min_slider_value; - var max_slider_value = this.max_slider_value; - var image = this.image; - - $(slider_id).val([min_slider_value, max_slider_value]); - - Caman(image.canvas_id, function() { - this.idmc_set_min_max_pixel_values(min_slider_value, max_slider_value); - this.render(); - }); -} - -// Inspired by: -// http://mihai.sucan.ro/coding/svg-or-canvas/histogram.html - -// Check this out: -// https://github.com/devongovett/png.js/blob/master/png.js - -PreviewCaman.prototype.draw_histogram = function(image_pixel_data) { - var hist_canvas = $(this.histogram.canvas_id)[0]; - var hist_context = hist_canvas.getContext('2d'); - var pixel_bins = this.histogram.data; - var nr_pixel_bins = pixel_bins.length; - - // Update histogram dimesions - - this.histogram_dim_update(); - - // Clear histogram canvas - - this.clear_canvas(hist_canvas); - - // The min/max pixel bins are not displayed - // because pixels masked out (cutoff min/max) at PreviewCaman generation - // are placed in those bins and therefore overrepresented - - pixel_bins[0] = 0; - pixel_bins[pixel_bins.length-1] = 0; - - // Find maximum - - max_count = Math.max.apply(Math, pixel_bins); - - // Draw histogram - - // Define line and fill color - - hist_context.strokeStyle = '#000000'; - hist_context['fillStyle'] = '#000000'; - - // Draw border - - hist_context.beginPath(); - hist_context.moveTo(0, hist_canvas.height); - hist_context.rect(0, 0, hist_canvas.width, hist_canvas.height); - hist_context.stroke(); - - // Draw histogram - - var border_size = hist_context.lineWidth; - var max_curve_width = hist_canvas.width; - var min_curve_x_pos = 0; - var max_curve_x_pos = hist_canvas.width; - - var max_curve_height = hist_canvas.height - border_size; - var min_curve_y_pos = hist_canvas.height - border_size; - var max_curve_y_pos = border_size; - - // Start in lower left corner - - hist_context.beginPath(); - hist_context.moveTo(0, hist_canvas.height); - - // Draw curve - - for (var x, y, i = 0; i < nr_pixel_bins; i++) { - if (!(i in pixel_bins)) { - continue; - } - y = Math.round((pixel_bins[i]/max_count)*max_curve_height); - console.debug('i: ' + i + ', x: ' + x + ', y: ' + y + ', pixel_bins[i]: ' + pixel_bins[i] + ', max_count: ' + max_count); - x = Math.round((i/(nr_pixel_bins-1))*max_curve_width); - - hist_context.lineTo(x, min_curve_y_pos - y); - } - - // End in lower right corner - - hist_context.lineTo(hist_canvas.width, hist_canvas.height); - - // Draw stroke - - hist_context.stroke(); - - // Fill curve - - hist_context.fill(); - hist_context.closePath(); - - // Update min max values - - this.update_preview_min_max_values(); -} diff --git a/mig/images/js/preview-paraview.js b/mig/images/js/preview-paraview.js deleted file mode 100644 index 416f59de7..000000000 --- a/mig/images/js/preview-paraview.js +++ /dev/null @@ -1,1076 +0,0 @@ -/* - -# -# --- BEGIN_HEADER --- -# -# paraview - ParaviewWeb render library -# Copyright (C) 2003-2016 The MiG Project lead by Brian Vinter -# -# This file is part of MiG. -# -# MiG is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public Licethnse as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# MiG is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# -- END_HEADER --- -# - -*/ - -/* - -This module is based on PreviewParaviewWeb: http://paraviewweb.kitware.com/ - -ParaView License: http://www.paraview.org/paraview-license - -ParaView uses a permissive BSD license that enables -the broadest possible audience, including commercial organizations, -to use the software, royalty free, for most purposes. -In addition, there are other licenses that are applicable -because of other packages leveraged by ParaView or developed by collaborators. -Lastly, there are specific packages for the ParaView binaries available -on paraview.org that have applicable licenses. -These additional licenses are detailed at the bottom of this page. -Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc. -Sandia National Laboratories, New Mexico PO Box 5800 Albuquerque, NM 87185 -Kitware Inc., 28 Corporate Drive, Clifton Park, NY 12065, USA - -Under the terms of Contract DE-AC04-94AL85000, -there is a non-exclusive license for use of this work -by or on behalf of the U.S. Government. - -Redistribution and use in source and binary forms, -with or without modification, are permitted provided that -the following conditions are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -Neither the name of Kitware nor the names of any contributors -may be used to endorse or promote products derived from this software -without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -http://www.paraview.org/paraview-license/ - -Copyright (c) 2010, Ryan LeFevre -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Ryan LeFevre nor the names of its contributors may be - used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - -/*! vtkWeb/ParaViewWeb - v2.0 - 2015-08-06 -* http://www.kitware.com/ -* Copyright (c) 2015 Kitware; Licensed BSD */ -/** - * vtkWebLoader JavaScript Library. - * - * vtkWebLoader use the vtkWeb namespace to manage JavaScript dependency and more specifically - * vtkWeb dependencies. - * - * @class vtkWebLoader - * - * @singleton - * - * ORG: /images/lib/ParaView/lib/core/vtkweb-loader.js - * - */ -(function (GLOBAL) { - AUTOBAHN_DEBUG = false; - - var vtkWebLibs = { - "core" : [ - "/images/lib/ParaView/ext/core/autobahn.js", - "/images/lib/ParaView/ext/core/gl-matrix.js", - "/images/lib/ParaView/ext/core/jquery.hammer.js", - "/images/lib/ParaView/ext/core/vgl.js", - "/images/lib/ParaView/lib/core/vtkweb-all.js" - ], - "core-min": [ - "/images/lib/ParaView/ext/core/autobahn.min.js", - "/images/lib/ParaView/ext/core/gl-matrix-min.js", - "/images/lib/ParaView/ext/core/jquery.hammer.min.js", - "/images/lib/ParaView/ext/core/vgl.min.js", - "/images/lib/ParaView/lib/core/vtkweb-all.min.js" - ], - "bootstrap": [ - "/images/lib/ParaView/ext/bootstrap/js/bootstrap.min.js", - "/images/lib/ParaView/ext/bootstrap/css/bootstrap-responsive.min.css", - "/images/lib/ParaView/ext/bootstrap/css/bootstrap.min.css" - ], - "fontello": [ - "/images/lib/ParaView/ext/fontello/css/animation.css", - "/images/lib/ParaView/ext/fontello/css/fontello.css" - ], - "color": [ - "/images/lib/ParaView/ext/jscolor/jscolor.js" - ], - "filebrowser": [ - "/images/lib/ParaView/ext/pure/pure.min.js", - "/images/lib/ParaView/lib/widgets/FileBrowser/vtkweb-widget-filebrowser.js", - "/images/lib/ParaView/lib/widgets/FileBrowser/vtkweb-widget-filebrowser.tpl", - "/images/lib/ParaView/lib/widgets/FileBrowser/vtkweb-widget-filebrowser.css" - ], - "pv-pipeline": [ - "/images/lib/ParaView/ext/jquery-ui/jquery-ui-1.10.0.css", - "/images/lib/ParaView/ext/jquery-ui/jquery-ui-1.10.0.min.js", - "/images/lib/ParaView/lib/css/paraview.ui.pipeline.css", - "/images/lib/ParaView/lib/js/paraview.ui.pipeline.js", - ], - "pv-toolbar": [ - "/images/lib/ParaView/lib/css/paraview.ui.toolbar.css", - "/images/lib/ParaView/lib/css/paraview.ui.toolbar.vcr.css", - "/images/lib/ParaView/lib/css/paraview.ui.toolbar.viewport.css", - "/images/lib/ParaView/lib/css/paraview.ui.toolbar.connect.css", - "/images/lib/ParaView/lib/js/paraview.ui.toolbar.js", - "/images/lib/ParaView/lib/js/paraview.ui.toolbar.vcr.js", - "/images/lib/ParaView/lib/js/paraview.ui.toolbar.viewport.js", - "/images/lib/ParaView/lib/js/paraview.ui.toolbar.connect.js" - ], - "jquery-ui": [ - "/images/lib/ParaView/ext/jquery-ui/jquery-ui-1.10.0.css", - "/images/lib/ParaView/ext/jquery-ui/jquery-ui-1.10.0.min.js" - ], - "d3":[ - "/images/lib/ParaView/ext/d3/d3.v2.js" - ], - "nvd3":[ - "/images/lib/ParaView/ext/nvd3/nv.d3.css", - "/images/lib/ParaView/ext/nvd3/nv.d3.js" - ], - "rickshaw": [ - "/images/lib/ParaView/ext/rickshaw/rickshaw.min.css", - "/images/lib/ParaView/ext/rickshaw/rickshaw.min.js" - ], - "widgets": [ - "/images/lib/ParaView/ext/pure/pure.min.js", - "/images/lib/ParaView/ext/d3/d3.v2.js", - "/images/lib/ParaView/ext/rickshaw/rickshaw.min.css", - "/images/lib/ParaView/ext/rickshaw/rickshaw.min.js", - "/images/lib/ParaView/ext/fontello/css/animation.css", - "/images/lib/ParaView/ext/fontello/css/fontello.css", - "/images/lib/ParaView/lib/widgets/FileBrowser/vtkweb-widget-filebrowser.tpl", - "/images/lib/ParaView/lib/widgets/TreeWidget/vtkweb-widget-tree.tpl", - "/images/lib/ParaView/lib/widgets/vtkweb-widgets-min.css", - "/images/lib/ParaView/lib/widgets/vtkweb-widgets-min.js" - ], - /* NOTE: bootstrap.min.js conflicts with our dialog buttons */ - "pv-visualizer": [ - "/images/lib/ParaView/ext/fontello/css/animation.css", - "/images/lib/ParaView/ext/fontello/css/fontello.css", - "/images/lib/ParaView/ext/bootstrap3/js/bootstrap.min.js", - "/images/lib/ParaView/lib/js/paraview.ui.action.list.js", - "/images/lib/ParaView/lib/js/paraview.ui.files.js", - "/images/lib/ParaView/lib/js/paraview.ui.data.js", - "/images/lib/ParaView/lib/js/paraview.ui.svg.pipeline.js", - "/images/lib/ParaView/lib/js/paraview.ui.opacity.editor.js", - "/images/lib/ParaView/lib/css/paraview.ui.opacity.editor.css", - "/images/lib/ParaView/lib/js/paraview.ui.color.editor.js", - "/images/lib/ParaView/lib/css/paraview.ui.color.editor.css" - ], - "pv-preview-visualizer": [ - "/images/lib/ParaView/ext/fontello/css/animation.css", - "/images/lib/ParaView/ext/fontello/css/fontello.css", - "/images/lib/ParaView/lib/js/paraview.ui.svg.pipeline.js", - "/images/lib/ParaView/lib/js/paraview.ui.proxy.editor.js", - ] - }, - modules = [], - script = document.getElementsByTagName("script")[document.getElementsByTagName("script").length - 1], - basePath = "", - extraScripts = []; - - // --------------------------------------------------------------------- - function loadCss(url) { - var link = document.createElement("link"); - link.type = "text/css"; - link.rel = "stylesheet"; - link.href = url; - head = document.getElementsByTagName("head")[0]; - head.insertBefore(link, head.childNodes[0]); - } - - // --------------------------------------------------------------------- - function loadJavaScript(url) { - document.write(''); - } - - // --------------------------------------------------------------------- - function loadTemplate(url) { - var templates = document.getElementById("vtk-templates"); - if(templates === null) { - templates = document.createElement("div"); - templates.setAttribute("style", "display: none;"); - templates.setAttribute("id", "vtk-templates"); - document.getElementsByTagName("body")[0].appendChild(templates); - } - - // Fetch template and append to vtk-templates - var request = makeHttpObject(); - request.open("GET", url, true); - request.send(null); - request.onreadystatechange = function() { - if (request.readyState == 4) { - var content = templates.innerHTML; - content += request.responseText; - templates.innerHTML = content; - } - }; - } - - // --------------------------------------------------------------------- - - function makeHttpObject() { - try { - return new XMLHttpRequest(); - } - catch (error) {} - try { - return new ActiveXObject("Msxml2.XMLHTTP"); - } - catch (error) {} - try { - return new ActiveXObject("Microsoft.XMLHTTP"); - } - catch (error) {} - - throw new Error("Could not create HTTP request object."); - } - - // --------------------------------------------------------------------- - function _endWith(string, end) { - return string.lastIndexOf(end) === (string.length - end.length); - } - - // --------------------------------------------------------------------- - function loadFile(url) { - if(_endWith(url, ".js")) { - loadJavaScript(url); - } else if(_endWith(url, ".css")) { - loadCss(url); - } else if(_endWith(url, ".tpl")) { - loadTemplate(url); - } - } - - // --------------------------------------------------------------------- - // Extract modules to load - // --------------------------------------------------------------------- - try { - modules = script.getAttribute("load").split(","); - for(var j in modules) { - modules[j] = modules[j].replace(/^\s+|\s+$/g, ''); // Trim - } - } catch(e) { - // We don't care we will use the default setup - } - - // --------------------------------------------------------------------- - // Extract extra script to load - // --------------------------------------------------------------------- - try { - extraScripts = script.getAttribute("extra").split(","); - for(var j in extraScripts) { - extraScripts[j] = extraScripts[j].replace(/^\s+|\s+$/g, ''); // Trim - } - } catch(e) { - // We don't care we will use the default setup - } - - // --------------------------------------------------------------------- - // If no modules have been defined, just pick the default - // --------------------------------------------------------------------- - if(modules.length == 0) { - //modules = [ "core-min" ]; - modules = [ "core" ]; - } - - // --------------------------------------------------------------------- - // Extract basePath - // --------------------------------------------------------------------- - var lastSlashIndex = script.getAttribute("src").lastIndexOf('lib/core/vtkweb-loader'); - if(lastSlashIndex != -1) { - basePath = script.getAttribute("src").substr(0, lastSlashIndex); - } - - // --------------------------------------------------------------------- - // Add missing libs - // --------------------------------------------------------------------- - for(var i in modules) { - for(var j in vtkWebLibs[modules[i]]) { - var path = basePath + vtkWebLibs[modules[i]][j]; - loadFile(path); - } - } - - // --------------------------------------------------------------------- - // Add extra libs - // --------------------------------------------------------------------- - for(var i in extraScripts) { - loadFile(extraScripts[i]); - } - - // --------------------------------------------------------------------- - // Remove loader - // --------------------------------------------------------------------- - script.parentNode.removeChild(script); -}(window)); - - -// ======================================================================== -// Constructor -// ======================================================================== - -PreviewParaview = function (debug) { - console.debug('PreviewParaview: constructor'); - this.settings = { - visible: false, - active: false, - value_range: {min: 0, - max: 0} - }; - - this.volume_xdmf_path = null; - this.reset_pv_state(); -} - -PreviewParaview.prototype.reset_pv_state = function() { - var _this = this; - var pv_error = $.proxy(function(e){ - _this.workDone(); - console.error('PreviewParaview ERROR: ' + e.error); - }, _this); - - _this.pv_state = { - stop: vtkWeb.NoOp, - connectionInfo: null, - viewport: null, - pipeline: null, - proxyEditor: null, - settingsEditor: null, - rvSettingsProxyId: null, - saveOptionsEditor: null, - defaultSaveFilenames: { - 'data': 'server-data/savedData.vtk', - 'state': 'server-state/savedState.pvsm', - 'screen': 'server-images/savedScreen.png' }, - saveTypesMap: { - 'AMR Dataset (Deprecated)': 'vtm', - 'Composite Dataset': 'vtm', - 'Hierarchical DataSet (Deprecated)': 'vtm', - 'Image (Uniform Rectilinear Grid) with blanking': 'vti', - 'Image (Uniform Rectilinear Grid)': 'vti', - 'Multi-block Dataset': 'vtm', - 'Multi-group Dataset': 'vtm', - 'Multi-piece Dataset': 'vtm', - 'Non-Overlapping AMR Dataset': 'vtm', - 'Overlapping AMR Dataset': 'vtm', - 'Point Set': 'vts', - 'Polygonal Mesh': 'vtp', - 'Polygonal Mesh': 'vtp', - 'Rectilinear Grid': 'vtr', - 'Structured (Curvilinear) Grid': 'vts', - 'Structured Grid': 'vts', - 'Table': 'csv', - 'Unstructured Grid': 'vtu' - }, - currentSaveType: 'state', - infoManager: null, - busyElement: $('.busy').hide(), - notBusyElement: $('.not-busy').show(), - busyCount: 0, - paletteNameList: [], - pipelineDataModel: { - metadata: null, - source: null, - representation: null, - view: null, - sources: []}, - activeProxyId: 0, - module: {}, - vcrPlayStatus: false, - pipelineLoadedCallBack: null, - error: pv_error - }; - - this.pv_state.module.initializeVisualizer = $.proxy(this.initializeVisualizer, this); -} - -// ======================================================================== -// PreviewParaview HTML + CSS management -// ======================================================================== - -PreviewParaview.prototype.init_html = function() { - var html_out = '
'; - html_out += ''; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += '
'; - - $("#fm_preview_paraview").html(html_out); -} - -PreviewParaview.prototype.remove_paraview_html = function() { - $("#fm_preview_paraview").html(''); -} - - -PreviewParaview.prototype.update_viewport_css = function () { - // Override default viewport setup - var width, height; - - $("#fm_preview_paraview_viewport .renderers").css({ - "position": "static", - "height": "100%", - "width": "100%"}); - - var renderers_posistion = $("#fm_preview_paraview_viewport .renderers").position(); - var renders_width = $("#fm_preview_paraview_viewport .renderers").width(); - var renders_height = $("#fm_preview_paraview_viewport .renderers").height(); - - - $("#fm_preview_paraview_viewport .renderers .image").css({ - "top": renderers_posistion.top + "px", - "left": renderers_posistion.left + "px", - "width": renders_width + "px", - "height": renders_height + "px", - }); - - $("#fm_preview_paraview_viewport .renderers .vgl").css({ - "top": renderers_posistion.top + "px", - "left": renderers_posistion.left + "px", - "width": renders_width + "px", - "height": renders_height + "px", - }); - - $("#fm_preview_paraview_viewport .renderers .webgl").css({ - "top": renderers_posistion.top + "px", - "left": renderers_posistion.left + "px", - "width": renders_width + "px", - "height": renders_height + "px", - }); - - $("#fm_preview_paraview_viewport .mouse-listener").css({ - "top": renderers_posistion.top + "px", - "left": renderers_posistion.left + "px", - "width": renders_width + "px", - "height": renders_height + "px", - }); - $("#fm_preview_paraview_viewport .statistics").css({ - "top": renderers_posistion.top + "px", - "left": renderers_posistion.left + "px", - "width": renders_width + "px", - "height": renders_height + "px", - }); - $("#fm_preview_paraview_viewport .overlay").css({ - "top": renderers_posistion.top + "px", - "left": renderers_posistion.left + "px", - "width": renders_width + "px", - "height": renders_height + "px", - }); -} - -// ======================================================================== -// ViewPort management (active + visibility) -// ======================================================================== - -PreviewParaview.prototype.createViewportView = function(viewportSelector) { - console.debug('createViewportView'); - /* - $(viewportSelector).empty() - .bind('captured-screenshot-ready', onScreenshotCaptured); - */ - var session = this.pv_state.session; - var pv_state = this.pv_state; - - pv_state.viewport = vtkWeb.createViewport({session: session}); - pv_state.viewport.bind(viewportSelector); - this.update_viewport_css(); -} - -// ------------------------------------------------------------------------ - -PreviewParaview.prototype.updateView = function() { - console.debug('updateView'); - - var viewport = this.pv_state.viewport; - - if(viewport) { - this.update_viewport_css(); - viewport.invalidateScene(); - } -} - -// ------------------------------------------------------------------------ - -PreviewParaview.prototype.resetCamera = function() { - console.debug('resetCamera'); - - var viewport = this.pv_state.viewport; - - if(viewport) { - this.update_viewport_css(); - viewport.resetCamera(); - } -} - -// ======================================================================== -// Pipeline management (active + visibility) -// ======================================================================== - -PreviewParaview.prototype.createPipelineManagerView = function(pipelineSelector) { - console.debug('createPipelineManagerView'); - - var pipeline = $(pipelineSelector); - - var onProxyVisibilityChange = $.proxy(this.onProxyVisibilityChange, this); - var onPipelineDataChange = $.proxy(this.onPipelineDataChange, this); - - pipeline.pipelineSVG({session: this.pv_state.session}); - pipeline.bind('pipeline-visibility-change', onProxyVisibilityChange); - pipeline.bind('pipeline-data-change', onPipelineDataChange); - pipeline.trigger('pipeline-reload'); - this.pv_state.pipeline = pipeline; -} - -// ------------------------------------------------------------------------ - -PreviewParaview.prototype.onProxyVisibilityChange = function(proxy) { - console.debug('onProxyVisibilityChange'); - this.updateView(); -} - -// ------------------------------------------------------------------------ - -PreviewParaview.prototype.onPipelineDataChange = function(event) { - console.debug('onPipelineDataChange active: ' + event.active); - - var pipelineDataModel = this.pv_state.pipelineDataModel; - var proxyEditor = this.pv_state.proxyEditor; - // { active: active_proxy_id, view: view_id, sources: proxy_list } - - this.pv_state.activeProxyId = event.active; - - // Update data model - - pipelineDataModel.sources = event.sources; - - // Handle the new active proxy - if(event.active === '0') { - $('.need-input-source').hide(); - proxyEditor.empty(); - this.updateView(); - } else { - $('.need-input-source').show(); - pipelineDataModel.metadata = this.getProxyMetaData(event.active); - pipelineDataModel.source = null; - pipelineDataModel.representation = null; - if(pipelineDataModel.metadata) { - this.loadProxy(pipelineDataModel.metadata.id, 'source'); - this.loadProxy(pipelineDataModel.metadata.rep, 'representation'); - if(pipelineDataModel.view === null) { - console.debug('onPipelineDataChange - > loadProxy'); - this.loadProxy(event.view, 'view'); - } - } - } -} - -// ======================================================================== -// Proxy Editor management (update + delete) -// ======================================================================== - -PreviewParaview.prototype.createProxyEditorView = function(proxyEditorSelector) { - console.debug('createProxyEditorView'); - this.pv_state.proxyEditor = $(proxyEditorSelector); -} - -// ------------------------------------------------------------------------ - -PreviewParaview.prototype.onProxyApply = function(event) { - var _this = this; - var session = _this.pv_state.session; - - console.debug('onProxyApply'); - - _this.startWorking(); - var invalidatePipeline = $.proxy(_this.invalidatePipeline, _this); - - session.call('pv.proxy.manager.update', [event.properties]).then(invalidatePipeline, invalidatePipeline); - - // Args: representation, colorMode, arrayLocation='POINTS', arrayName='', vectorMode='Magnitude', vectorComponent = 0, rescale=False - var args = [].concat(event.colorBy.representation, event.colorBy.mode, event.colorBy.array, event.colorBy.component); - this.startWorking(); - session.call('pv.color.manager.color.by', args).then(this.invalidatePipeline, this.pv_state.error); - // Update palette ? - if(event.colorBy.palette) { - this.startWorking(); - session.call('pv.color.manager.select.preset', [ event.colorBy.representation, event.colorBy.palette ]).then(invalidatePipeline, this.pv_state.error); - } -} - -// ------------------------------------------------------------------------ - -PreviewParaview.prototype.onRescaleTransferFunction = function(event) { - console.debug('onRescaleTransferFunction'); - - var _this = this; - var proxyEditor = _this.pv_state.proxyEditor; - var viewPort = _this.pv_state.viewPort; - var session = _this.pv_state.session; - - console.debug('onRescaleTransferFunction'); - console.debug('onRescaleTransferFunction: ' + Object.keys(event)); - console.debug('onRescaleTransferFunction => event.id: ' + event.id); - console.debug('onRescaleTransferFunction => type: ' + event.type + ', typeof: ' + typeof(event.type)); - console.debug('onRescaleTransferFunction => mode: ' + event.mode + ', typeof: ' + typeof(event.mode)); - - _this.startWorking(); - var options = { proxyId: event.id, type: event.mode }; - if(event.mode === 'custom') { - options.min = event.min; - options.max = event.max; - } - console.debug('onRescaleTransferFunction options.proxyId: ' + options.proxyId); - console.debug('onRescaleTransferFunction options.type: ' + options.type); - console.debug('onRescaleTransferFunction options.min: ' + options.min); - console.debug('onRescaleTransferFunction options.max: ' + options.max); - - session.call('pv.color.manager.rescale.transfer.function', [options]).then(function(arg) { - if (arg['success'] === true) { - _this.pv_state.viewPort.invalidateScene(); - proxyEditor.trigger({ - 'type': 'update-scalar-range-values', - 'min': successResult.range.min, - 'max': successResult.range.max - }); - session.call('pv.color.manager.rgb.points.get', [event.colorBy.array[1]]).then(function(result) { - proxyEditor.trigger({ - 'type': 'notify-new-rgb-points-received', - 'rgbpoints': result - }); - _this.workDone(); - }, _this.pv_state.error); - } else { - _this.workDone(); - } - }, _this.pv_state.error); - -} - -// ------------------------------------------------------------------------ - -PreviewParaview.prototype.onNewProxyLoaded = function() { - //console.debug('onNewProxyLoaded'); - var pipelineDataModel = this.pv_state.pipelineDataModel; - var proxyEditor = this.pv_state.proxyEditor; - var paletteNameList = this.pv_state.paletteNameList; - //console.debug('onNewProxyLoaded metadata keys: ' + Object.keys(pipelineDataModel['metadata'])); - console.debug('onNewProxyLoaded id: ' + pipelineDataModel['metadata']['id'] + - ', name: ' + pipelineDataModel['metadata']['name'] + - ', rep: ' + pipelineDataModel['metadata']['rep']); - - if(pipelineDataModel.metadata && pipelineDataModel.source && pipelineDataModel.representation && pipelineDataModel.view) { - var colorBy = pipelineDataModel.representation.colorBy, - props = [], - ui = [], - options = {}; - - try { - proxyEditor.proxyEditor(pipelineDataModel.metadata.name, - pipelineDataModel.metadata.leaf, - pipelineDataModel.metadata.id, - props, - ui, - pipelineDataModel.source.data.arrays, - paletteNameList, - colorBy, - options); - } catch(err) { - console.log(err); - } - - // Handle callback if any - if(this.pv_state.pipelineLoadedCallBack) { - this.pv_state.pipelineLoadedCallBack(); - this.pv_state.pipelineLoadedCallBack = null; - } - - // Handle automatic reset camera - if(pipelineDataModel.sources.length === 1) { - this.resetCamera(); - } else { - this.updateView(); - } - } -} - - -// ======================================================================== -// Main - Visualizer Setup -// ======================================================================== - -PreviewParaview.prototype.initializeVisualizer = function(viewportSelector, - pipelineSelector, - proxyEditorSelector) { - console.debug('initializeVisualizer'); - - // Create panels - - this.createViewportView(viewportSelector); - this.createPipelineManagerView(pipelineSelector); - this.createProxyEditorView(proxyEditorSelector); - - // Set initial state - - this.pv_state.proxyEditor.empty(); -} - -// ======================================================================== -// Main callback -// ======================================================================== - -PreviewParaview.prototype.invalidatePipeline = function(arg) { - console.debug('invalidatePipeline'); - - var pv_state = this.pv_state; - - if(arg && arg.hasOwnProperty('id')) { - // Update active proxy in pipeline - this.activeProxy(arg.id); - } - pv_state.pipeline.trigger('pipeline-reload'); - pv_state.viewport.resetViewId(); - pv_state.viewport.invalidateScene(); - this.workDone(); -} - - -// ======================================================================== -// Busy feedback -// ======================================================================== - -PreviewParaview.prototype.startWorking = function() { - this.pv_state.busyCount++; -} - -// ------------------------------------------------------------------------ - -PreviewParaview.prototype.workDone = function() { - this.pv_state.busyCount--; -} - -// ======================================================================== -// Helper methods -// ======================================================================== - -PreviewParaview.prototype.activeProxy = function(newActiveProxy) { - console.debug('activeProxy: ' + newActiveProxy); - if(newActiveProxy) { - this.pv_state.pipeline.data('pipeline').active_proxy = newActiveProxy; - } - return this.pv_state.pipeline.data('pipeline').active_proxy; -} - -// ------------------------------------------------------------------------ - -PreviewParaview.prototype.getProxyMetaData = function(id) { - console.debug('getProxyMetaData: ' + id); - - var pipelineDataModel = this.pv_state.pipelineDataModel; - var list = pipelineDataModel.sources, - count = list.length; - - while(count--) { - if(list[count].id === id) { - return list[count]; - } - } - return null; -} - -// ------------------------------------------------------------------------ - -PreviewParaview.prototype.loadProxy = function(proxy_id, name) { - console.debug('loadProxy -> id: ' + proxy_id + ', name: ' + name); - var _this = this; - var pipelineDataModel = _this.pv_state.pipelineDataModel; - var session = _this.pv_state.session; - if(session) { - _this.startWorking(); - session.call("pv.proxy.manager.get", [proxy_id]).then( - function(proxy){ - _this.workDone(); - pipelineDataModel[name] = proxy; - console.debug('loadProxy -> onNewProxyLoaded: ' + proxy); - _this.onNewProxyLoaded(); - }, _this.pv_state.error); - } -} - -// ======================================================================== -// IDMC methods -// ======================================================================== - -PreviewParaview.prototype.set_volume_xdmf = function(volume_xdmf_filepath) { - this.volume_xdmf_filepath = './' + volume_xdmf_filepath; - console.debug('set_volume_xdmf: volume_xdmf_filepath: ' + this.volume_xdmf_filepath); -} - -PreviewParaview.prototype.get_value_range = function() { - return {min: this.settings.value_range.min, - max: this.settings.value_range.max}; -} - -PreviewParaview.prototype.set_value_range = function(min_value, max_value, callback) { - this.settings.value_range.min = min_value; - this.settings.value_range.max = max_value; - - if (typeof callback === "function") { - callback(); - } -} - -PreviewParaview.prototype.start_rendering = function() { - console.debug('PreviewParaview.start_rendering') - this.render_volume_xdmf(); -} - -PreviewParaview.prototype.render_volume_xdmf = function() { - var _this = this; - var fullpathFileList = _this.volume_xdmf_filepath; - var session = _this.pv_state.session; - - console.debug('PreviewParaview.render_volume_xdmf: ' + fullpathFileList); - - session.call("pv.proxy.manager.create.reader", [fullpathFileList]).then( - function(arg) { - console.debug('pv.proxy.manager.create.reader: ' + arg.id); - _this.pv_state.pipelineLoadedCallBack = function(arg) { - console.debug('pipelineLoadedCallBack'); - - var pipelineDataModel = _this.pv_state.pipelineDataModel; - - var metadata = pipelineDataModel.metadata; - var src_props = pipelineDataModel.source.properties; - var view_props = pipelineDataModel.view.properties; - var repr_props = pipelineDataModel.representation.properties; - - // Set source properties - - var src_count = src_props.length; - var prop; - var idx; - var volume_name; - var new_props = []; - - - for(idx = 0; idx < src_count; ++idx) { - prop = src_props[idx]; - - if (prop.name === 'PointArrayStatus') { - volume_name = prop.value; - - } - if (prop.name === 'GridStatus' && prop.value == '') { - // For some reason (reusing an empty GridStatus fails) - console.debug('skipping empty property: ' + prop.name); - } - else { - new_props.push(prop); - } - } - - // Set representation properties - - var repr_count = repr_props.length; - - for(idx = 0; idx < repr_count; ++idx) { - prop = repr_props[idx]; - - if (prop.name === 'Representation') { - prop.value = 'Volume'; - } - - new_props.push(prop); - } - - var view_count = view_props.length; - - for(idx = 0; idx < view_count; ++idx) { - prop = view_props[idx]; - new_props.push(prop); - } - - - // Set color palette - - var colorBy = pipelineDataModel.representation.colorBy; - - colorBy.palette = 'X Ray'; - colorBy.mode = 'ARRAY'; - colorBy.array [1] = new String(volume_name); - colorBy.array[2] = ''; - - // Apply changes - - _this.onProxyApply({ - colorBy: colorBy, - properties: new_props - }); - - // Rescale - - value_range = _this.get_value_range(); - - _this.onRescaleTransferFunction({ - id: pipelineDataModel.source.id, - type: 'rescale-transfer-function', - mode: 'custom', - min: value_range.min, - max: value_range.max - }); - - - }; - _this.invalidatePipeline(arg); - }, _this.pv_state.error); -} - -PreviewParaview.prototype.open = function() { - console.debug('PreviewParaview.launch: ' + Object.keys(this)); - var _this = this; - - // Start with fresh pv_State - _this.reset_pv_state(); - - var pv_state = this.pv_state; - var pv = pv_state.module; - var start_rendering = $.proxy(this.start_rendering, this); - - var config = { - sessionManagerURL: vtkWeb.properties.sessionManagerURL, - application: "visualizer" - }, - start = function(connectionInfo) { - console.debug('PreviewParaview launch start'); - - $(".app-wait-start-page").css("visibility", 'hidden'); - $(".app-wait-start-page").css("height", '0%'); - - pv_state.connectionInfo = connectionInfo; - pv_state.session = connectionInfo.session; - - pv_state.module.initializeVisualizer( - ".pv-viewport", - ".pv-pipeline", - ".pv-proxy-editor" - ); - start_rendering(); - }; - - // Try to launch the Viz process - - this.init_html(); - - console.debug('PreviewParaview launch url: ' + config.sessionManagerURL); - vtkWeb.smartConnect(config, start, function(code,reason){ - console.debug('PreviewParaview connectionInfo closed, code: ' + ', reason: ' + reason); - }); -} - -PreviewParaview.prototype.close = function() { - var _this = this; - var pv_state = this.pv_state; - var session = pv_state.session; - var connectionInfo = pv_state.connectionInfo; - console.debug('closing paraview'); - - try { - console.debug('calling application.exit'); - session.call("application.exit", []); - connectionInfo.connection.close(); - - } catch(exception) { - console.debug('PreviewParaview.close exception: ' + exception); - } - - _this.reset_pv_state(); - _this.remove_paraview_html(); - console.debug('stopped paraview'); -} - -PreviewParaview.prototype.refresh = function(visible, callback) { - console.debug('paraview refresh: visible: ' + visible); - console.debug('paraview refresh: callback: ' + callback); - console.debug('paraview refresh: this.settings.visible : ' + this.settings.visible); - //this.debug_js_object(this); - if (this.settings.visible == true && visible == false) { - this.close(); - console.debug('paraview refresh -> close'); - } - else if (this.settings.visible == false && visible == true) { - this.open(); - console.debug('paraview refresh -> open'); - } - else if (this.settings.visible == true && visible == true) { - this.updateView(); - console.debug('paraview refresh -> update'); - } - - this.settings.visible = visible; - - if (typeof callback === "function") { - callback(); - } -} \ No newline at end of file diff --git a/mig/images/js/preview.js b/mig/images/js/preview.js deleted file mode 100644 index 400266305..000000000 --- a/mig/images/js/preview.js +++ /dev/null @@ -1,696 +0,0 @@ -/* -# -# --- BEGIN_HEADER --- -# -# preview - javascript based image preview library -# Copyright (C) 2003-2016 The MiG Project lead by Brian Vinter -# -# This file is part of MiG. -# -# MiG is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public Licethnse as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# MiG is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# -- END_HEADER --- -# -*/ - -Preview = function (layout, options, debug) { - //console.debug('Preview: constructor: ' + selfname); - console.debug('Preview: constructor'); - var _this = this; - _this.settings = { - layout: layout, - options: options, - debug: debug, - paraview: false, - volume: false, - caman: false, - visible: false, - height: 0, - zoom: 0, - min_zoom: 0, - max_zoom: 2, - last_zoom: 0, - }; - - var callback = function() { - var max_decimals = _this.get_format_decimals(); - _this.caman = new PreviewCaman(max_decimals, debug); - _this.paraview = new PreviewParaview(debug); - } - _this.init_html(callback); -} - -/* -// For Paraview DEBUG -setTimeout(function() { - console.debug('starting paraview'); - toggle_paraview(); -}, 1000); - // End: For Paraview DEBUG -*/ - -Preview.prototype.debug_js_object = function (js_object) { - console.debug('debug_js_object: '); - console.debug(JSON.stringify(js_object).split(",").join("'\n").split(":").join(": '").split("}").join("'}")); - console.debug('end debug_js_object: '); -} - -Preview.prototype.init_html = function(callback) { - var html_out = ''; - html_out += ''; - html_out += ''; - html_out += ''; - html_out += '
'; - html_out += '
'; - html_out += ' '; - html_out += '
'; - html_out += '
'; - html_out += ' '; - html_out += '
'; - html_out += '
'; - html_out += ' '; - html_out += '
'; - html_out += '
'; - html_out += ' '; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += ' '; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += ' '; - html_out += ' '; - html_out += ' '; - html_out += '
'; - html_out += '
'; - html_out += ' '; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += ' '; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += ' '; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += '
'; - html_out += ' '; - html_out += '
'; - - if(typeof callback === "function"){ - $("#fm_previews").html(html_out).promise().done(callback); - } else { - $("#fm_previews").html(html_out); - } -} - -Preview.prototype.init_tiles_HTML = function(image_meta) { - var right_html_out = ''; - var left_html_out = ''; - var image_filepath; - var image_path; - - $(".fm_previews input[name=fm_preview_base_path]").val(image_meta.base_path); - $(".fm_previews input[name=fm_preview_path]").val(image_meta.path); - $(".fm_previews input[name=fm_preview_filename]").val(image_meta.name); - $(".fm_previews input[name=fm_preview_extension]").val(image_meta.extension); - - preview_image_url = image_meta.preview_image_url; - - if (image_meta.path === '') { - image_path = image_meta.base_path; - } - else { - image_path = image_meta.base_path + image_meta.path + "/"; - } - image_filepath = image_path + image_meta.name; - - right_html_out += '

Image: ' + image_filepath + '

' - + '

Image Type: ' + image_meta.image_type + '

' - + '

Data Type: ' + image_meta.data_type + '

' - + '

Offset: ' + image_meta.offset + '

' - + '

X Dimension: ' + image_meta.x_dimension + '

' - + '

Y Dimension: ' + image_meta.y_dimension + '

' - + '

Min Value: ' + Number(image_meta.min_value).toExponential(this.get_format_decimals()) + '

' - + '

Max Value: ' + Number(image_meta.max_value).toExponential(this.get_format_decimals()) + '

' - + '

Mean Value: ' + Number(image_meta.mean_value).toExponential(this.get_format_decimals()) + '

' - + '

Median Value: ' + Number(image_meta.median_value).toExponential(this.get_format_decimals()) + '

'; - - // TODO: Move input fields HTML to fileman.py ? - - left_html_out += '' - + '' - + '' - + '' - + '' - + '

' - + '

' - + '

' - - $("#fm_preview_right_output").html(right_html_out); - $("#fm_preview_left_output").html(left_html_out); -} - -Preview.prototype.update_fm_layout = function(layout) { - var fileManagerInnerHeight = layout.fm.innerHeight; - var fileFolderInnerHeight = layout.fm.fileFolderInnerHeight; - var previewInnerHeight = 0; - var previewInnerHeightFrac = 0.50; - var centerTileWidthFrac = 0.40; - var previewWidth = $("#fm_filemanager .fm_previews").outerWidth() - /* NOTE: compensate for rounding(?) with a couple of extra pixels. - preview overflow with FF@Linux in 1920x1080 resolution with zoom twice - */ - var previewInnerWidth = $("#fm_filemanager .fm_previews").width() - - $("#fm_filemanager .fm_preview_menubar").outerWidth() - 2; - var previewCenterTileWidth = Math.floor(previewInnerWidth * centerTileWidthFrac); - var previewLeftTileWidth = Math.floor((previewInnerWidth - previewCenterTileWidth)/2); - var previewRightTileWidth = previewLeftTileWidth; - - - if (this.settings.zoom == 0) { - previewInnerHeight = 0; - fileFolderInnerHeight = fileManagerInnerHeight; - } - else if (this.settings.zoom == 1) { - previewInnerHeight = fileFolderInnerHeight * previewInnerHeightFrac; - - fileFolderInnerHeight = fileManagerInnerHeight - previewInnerHeight; - } - else if (this.settings.zoom > 1) { - previewInnerHeight = fileManagerInnerHeight; - fileFolderInnerHeight = 0; - } - - layout.fm.fileFolderInnerHeight = fileFolderInnerHeight; - layout.fm.preview = { - width: previewWidth, - innerHeight: previewInnerHeight, - innerWidth: previewInnerWidth, - leftTileWidth: previewLeftTileWidth, - centerTileWidth: previewCenterTileWidth, - rightTileWidth: previewRightTileWidth - }; - return layout; -} - -Preview.prototype.update_html_layout = function(callback) { - var layout = (typeof this.settings.layout === "function") ? - _this.settings.layout() : - _this.settings.layout; - $("#fm_filemanager .fm_previews").css("height", layout.fm.preview.innerHeight + "px"); - $("#fm_filemanager .fm_preview_caman").css("width", layout.fm.preview.innerWidth + "px"); - $("#fm_filemanager .fm_preview_left_tile").css("width", layout.fm.preview.leftTileWidth + "px"); - $("#fm_filemanager .fm_preview_center_tile").css("width", layout.fm.preview.centerTileWidth + "px"); - $("#fm_filemanager .fm_preview_right_tile").css("width", layout.fm.preview.rightTileWidth + "px"); - $("#fm_filemanager .fm_preview_paraview").css("width", layout.fm.preview.innerWidth + "px"); - $("#fm_filemanager .pv-viewport").css("width", layout.fm.preview.innerWidth + "px"); -} - -Preview.prototype.init_image_settings = function(image_settings, image_meta, volume_meta) { - - // Check if preview files are ready - - if (image_settings.image_settings_status.toLowerCase() == 'ready' ) { - $("#preview_histogram_set_cutoff_button").attr('disabled', false); - } else { - $("#preview_histogram_set_cutoff_button").attr('disabled', true); - - } - - - // Check if preview volumes are ready - - if (volume_meta != null && image_settings.volume_settings_status.toLowerCase() == 'ready') { - this.paraview.set_volume_xdmf(volume_meta.preview_xdmf_filepath); - $("#fm_preview_menubar_paraview").css('opacity', 1.0); - this.settings.volume = true; - } else { - $("#fm_preview_menubar_paraview").css('opacity', 0.5); - this.settings.volume = false; - console.debug('volume_meta is null or _NOT_ ready'); - } -} - -Preview.prototype.bind_buttons = function() { - var _this = this; - $("#fm_preview_menubar_zoom_out").on('click', - function(event) { - console.debug('fm_preview_menubar_zoom_out'); - _this.zoom_out(); - }); - - $("#fm_preview_menubar_zoom_in").on('click', - function(event) { - console.debug('fm_preview_menubar_zoom_in'); - _this.zoom_in(); - }); - - $("#fm_preview_menubar_refresh").on('click', - function(event) { - console.debug('fm_preview_menubar_refresh'); - _this.refresh(); - }); - - $("#fm_preview_menubar_paraview").on('click', - function(event) { - console.debug('fm_preview_menubar_paraview'); - _this.toggle_paraview(); - }); - - $("#preview_histogram_reset_button").on('click', - function(event) { - _this.caman.reset(); - }); - - $("#preview_histogram_set_cutoff_button").on('click', - function(event) { - - // Disable button - - $("#preview_histogram_set_cutoff_button").attr('disabled', true); - - var path = $(".fm_previews input[name=fm_preview_base_path]").val(); - var extension = $(".fm_previews input[name=fm_preview_extension]").val(); - var min_value = $("#fm_preview_left_output input[name='current_min_value']").val(); - var max_value = $("#fm_preview_left_output input[name='current_max_value']").val(); - - var error_callback = function(errors) { - $("#fm_preview_left_output").html(errors); - console.error(errors); - } - - var warning_callback = function(warnings) { - $("#fm_preview_left_output").html(warnings); - console.warn(warnings); - } - - var ok_callback = function(image_setting, image_meta, volume_meta) { - console.debug('preview_histogram_set_cutoff_button OK'); - } - _this.update_image_dir(path, - extension, - min_value, - max_value, - ok_callback, - error_callback, - warning_callback); - } - ); -} - -Preview.prototype.get_preview_histogram_data = function(image_meta) { - return new Uint32Array(image_meta.preview_histogram); -} - -Preview.prototype.get_format_decimals = function() { - var format_decimals = 4; - - return format_decimals; -} - -Preview.prototype.open = function(path) { - // Disable content depending buttons by default - var _this = this; - - var error_callback = function(errors) { - $("#fm_preview_right_output").html(errors); - $("#fm_preview_left_output").html(''); - console.error(errors); - } - var warning_callback = function(warnings) { - $("#fm_preview_right_output").html(warnings); - $("#fm_preview_left_output").html(''); - console.warn(warnings); - } - var ok_callback = function(image_setting, image_meta, volume_meta) { - var preview_histogram = _this.get_preview_histogram_data(image_meta); - _this.init_tiles_HTML(image_meta); - _this.init_image_settings(image_setting, image_meta, volume_meta); - _this.caman.set_histogram_data(preview_histogram); - _this.settings.zoom = 1; - _this.settings.caman = true; - _this.show(function() { - _this.caman.load(image_meta.preview_image_url); - }); - } - _this.get_image_file(path, ok_callback, error_callback, warning_callback); -} - -Preview.prototype.close = function() { - this.paraview.close(); -} - -Preview.prototype.refresh = function(callback) { - var _this = this; - console.debug('refresh callback: ' + callback); - - var refresh_callback = function() { - console.debug('refresh_callback: zoom: ' + _this.settings.zoom + ', caman: ' + _this.settings.caman + ', paraview: ' + _this.settings.paraview); - _this.caman.refresh(_this.settings.caman, callback); - _this.paraview.refresh(_this.settings.paraview, callback); - } - _this.show(refresh_callback); -} - -Preview.prototype.zoom_out = function(callback) { - console.debug('zoom_out: paraview: ' + this.settings.paraview); - console.debug('zoom_out: caman: ' + this.settings.caman); - console.debug('zoom_out: zoom: ' + this.settings.zoom); - if (this.settings.paraview == true) { - this.toggle_paraview(callback); - } - else if (this.settings.caman == true) { - if (this.settings.zoom > this.settings.min_zoom) { - this.settings.last_zoom = this.settings.zoom; - this.settings.zoom -= 1; - if (this.settings.zoom == this.settings.min_zoom) { - this.settings.caman = false; - } - console.debug('zoom_out check: paraview: ' + this.settings.paraview); - console.debug('zoom_out check: caman: ' + this.settings.caman); - console.debug('zoom_out check: zoom: ' + this.settings.zoom); - this.refresh(callback); - } - } -} - -Preview.prototype.zoom_in = function(callback) { - if (this.settings.paraview == false && - this.settings.zoom < this.settings.max_zoom) { - this.settings.caman = true; - this.settings.last_zoom = this.settings.zoom; - this.settings.zoom += 1; - this.refresh(callback); - } -} - -Preview.prototype.set_visibility_left_tile = function(visibility) { - $("#fm_preview_left_tile").css("visibility", visibility); - $("#fm_preview_left_tile_histogram").css("visibility", visibility); - $("#fm_preview_left_tile_histogram_actions").css("visibility", visibility); - $("#fm_preview_left_output").css("visibility", visibility); -} - -Preview.prototype.set_visibility_center_tile = function(visibility) { - $("#fm_preview_center_tile").css("visibility", visibility); -} - -Preview.prototype.set_visibility_right_tile = function(visibility) { - $("#fm_preview_right_tile").css("visibility", visibility); - $("#fm_preview_right_output").css("visibility", visibility); -} - -Preview.prototype.set_visibility_caman = function(visibility) { - $("#fm_preview_caman").css('visibility', visibility); - this.set_visibility_left_tile(visibility); - this.set_visibility_center_tile(visibility); - this.set_visibility_right_tile(visibility); -} -Preview.prototype.set_visibility_paraview = function(visibility) { - $("#fm_preview_paraview").css('visibility', visibility); -} - -Preview.prototype.set_visibility = function(visibility) { - $("#fm_preview_menubar").css('visibility', visibility); - var caman_visibility; - var paraview_visibility; - - if (this.settings.paraview == false) { - $("#fm_preview_caman").css('height', '100%'); - $("#fm_preview_paraview").css('height', '0%'); - caman_visibility = visibility; - paraview_visibility = 'hidden'; - } - else { - caman_visibility = 'hidden'; - $("#fm_preview_caman").css('height', '0%'); - $("#fm_preview_paraview").css('height', '100%'); - paraview_visibility = visibility; - } - - this.set_visibility_caman(caman_visibility); - this.set_visibility_paraview(paraview_visibility); -} - -Preview.prototype.show = function(callback) { - var _this = this; - var layout = (typeof this.settings.layout === "function") ? - _this.settings.layout() : - _this.settings.layout; - //console.debug('layout: ' + Object.keys(layout)); - //_this.debug_js_object(layout); - /*for (var key in Object.keys(layout)) { - console.debug('layout -> ' + key + ' : ' + layout[key]); - } - */ - console.debug('preview show'); - - - var visibility = (_this.settings.zoom == 0) ? - 'hidden' : - 'visible'; - var animate_speed = (_this.settings.zoom < _this.settings.last_zoom) ? - _this.settings.options.collapseSpeed : - _this.settings.options.expandSpeed; - var animate_easing = (_this.settings.zoom < _this.settings.last_zoom) ? - _this.settings.options.collapseEasing : - _this.settings.options.expandEasing; - $("#fm_filemanager .fm_folders").animate( - {height: layout.fm.fileFolderInnerHeight + 'px'}, - {duration: animate_speed, - easing: animate_easing}); - $("#fm_filemanager .fm_files").animate( - {height: layout.fm.fileFolderInnerHeight + 'px'}, - {duration: animate_speed, - easing: animate_easing}); - $("#fm_filemanager .fm_preview_caman").css("width", layout.fm.preview.innerWidth + "px"); - $("#fm_filemanager .fm_preview_left_tile").css("width", layout.fm.preview.leftTileWidth + "px"); - $("#fm_filemanager .fm_preview_center_tile").css("width", layout.fm.preview.centerTileWidth + "px"); - $("#fm_filemanager .fm_preview_right_tile").css("width", layout.fm.preview.rightTileWidth + "px"); - $("#fm_filemanager .fm_preview_paraview").css("width", layout.fm.preview.innerWidth + "px"); - $("#fm_filemanager .fm_previews").animate( - {height: layout.fm.preview.innerHeight + 'px'}, - {duration: animate_speed, - easing: animate_easing, - complete: function() { - _this.set_visibility(visibility); - if (typeof callback === "function") { - console.debug('show callback called: ' + callback); - callback(); - } - }}); -} - -Preview.prototype.toggle_paraview = function(callback) { - - console.debug('toggle_paraview'); - if (this.settings.volume == true) { - if (this.settings.paraview == true) { - this.settings.paraview = false; - this.settings.caman = true; - this.settings.zoom = this.settings.last_zoom; - //this.paraview.close(); - } - else { - this.settings.paraview = true; - this.settings.caman = false; - this.settings.last_zoom = this.settings.zoom; - this.settings.zoom = this.settings.max_zoom; - //callback = $.proxy(this.paraview.open, this.paraview); - } - - // TODO: Make contrast slider for volume instead of using the min/max from sliced view - - var min_value = $("#fm_preview_left_output input[name='current_min_value']").val(); - var max_value = $("#fm_preview_left_output input[name='current_max_value']").val(); - - var refresh_proxy = $.proxy(this.refresh, this, callback); - - console.debug('toggle_paraview zoom: ' + this.settings.zoom); - this.paraview.set_value_range(min_value, max_value, refresh_proxy); - } -} - -Preview.prototype.get_image_file = function(path, ok_callback, error_callback, warning_callback) { - console.debug('get_image_file -> path: ' + path); - - $.ajax({ - url: 'imagepreview.py', - data: { path: path, - output_format: 'json', - action: 'get', - }, - type: "GET", - dataType: "json", - cache: false, - success: function(jsonRes, textStatus) { - var i; - var errors = $(this).renderError(jsonRes); - var warnings = $(this).renderWarning(jsonRes); - var image_settings = null; - var image_meta = null; - var volume_meta = null; - - for (i = 0; i < jsonRes.length; i++) { - if (jsonRes[i].object_type == 'image_setting') { - image_setting = jsonRes[i]; - } else if (jsonRes[i].object_type == 'image_meta') { - image_meta = jsonRes[i]; - } else if (jsonRes[i].object_type == 'volume_meta') { - volume_meta = jsonRes[i]; - } - } - if (errors.length > 0) { - if (typeof error_callback === "function") { - console.error(errors); - } else { - error_callback(errors); - } - - } else if (warnings.length > 0) { - if (typeof warning_callback === "function") { - console.warn(warnings); - } else { - warning_callback(warnings); - } - } else { - if (typeof ok_callback === "function") { - ok_callback(image_setting, image_meta, volume_meta); - } - } - }, - error: function(jqXHR, textStatus, errorThrown) { - console.error("get_image_file error: " + errorThrown); - } - }); -} - - -Preview.prototype.get_image_dir = function( - path, - extension, - ok_callback, - error_callback, - warning_callback) { - - console.debug('get_image_dir -> path: ' + path + ', extension: ' + extension); - $.ajax({ - url: 'imagepreview.py', - data: { path: path, - extension: extension, - output_format: 'json', - action: 'get_setting', - }, - type: "GET", - dataType: "json", - cache: false, - success: function(jsonRes, textStatus) { - var i; - var errors = $(this).renderError(jsonRes); - var warnings = $(this).renderWarning(jsonRes); - var image_setting = null; - for (i = 0; i < jsonRes.length; i++) { - if (jsonRes[i].object_type == 'image_setting') { - image_setting = jsonRes[i]; - } - } - - if (errors.length > 0) { - if (typeof error_callback === "function") { - console.error(errors); - } else { - error_callback(errors); - } - } else if (warnings.length > 0) { - if (typeof warning_callback === "function") { - console.warn(warnings); - } else { - warning_callback(warnings); - } - } else { - if (typeof ok_callback === "function") { - ok_callback(image_setting); - } - } - }, - error: function(jqXHR, textStatus, errorThrown) { - console.error("get_image_dir error: " + errorThrown); - } - }); -} - -Preview.prototype.update_image_dir = function( - path, - extension, - preview_cutoff_min, - preview_cutoff_max, - ok_callback, - error_callback, - warning_callback) { - - console.debug('get_image_dir -> path: ' + path + ', extension: ' + extension); - - $.ajax({ - url: 'imagepreview.py', - data: { path: path, - extension: extension, - output_format: 'json', - action: 'update_setting', - preview_cutoff_min: preview_cutoff_min, - preview_cutoff_max: preview_cutoff_max, - }, - type: "POST", - dataType: "json", - cache: false, - success: function(jsonRes, textStatus) { - var i; - var errors = $(this).renderError(jsonRes); - var warnings = $(this).renderWarning(jsonRes); - var image_setting = null; - for (i = 0; i < jsonRes.length; i++) { - if (jsonRes[i].object_type == 'image_setting') { - image_setting = jsonRes[i]; - } - } - if (errors.length > 0) { - if (typeof error_callback === "function") { - console.error(errors); - } else { - error_callback(errors); - } - } else if (warnings.length > 0) { - if (typeof warning_callback === "function") { - console.warn(warnings); - } else { - warning_callback(warnings); - } - } else { - if (typeof ok_callback === "function") { - ok_callback(image_setting); - } - } - }, - error: function(jqXHR, textStatus, errorThrown) { - console.error("getImageDir error: " + errorThrown); - } - }); -} diff --git a/mig/images/lib/CamanJS b/mig/images/lib/CamanJS deleted file mode 120000 index 45dbf0c1a..000000000 --- a/mig/images/lib/CamanJS +++ /dev/null @@ -1 +0,0 @@ -CamanJS-4.1.1 \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/.gitignore b/mig/images/lib/CamanJS-4.1.1/.gitignore deleted file mode 100644 index a09ffe584..000000000 --- a/mig/images/lib/CamanJS-4.1.1/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.DS_Store -*.sublime-project -*.sublime-workspace -sftp-config.json -node_modules/ -dist/*.coffee diff --git a/mig/images/lib/CamanJS-4.1.1/.gitmodules b/mig/images/lib/CamanJS-4.1.1/.gitmodules deleted file mode 100644 index b3087377d..000000000 --- a/mig/images/lib/CamanJS-4.1.1/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule "test/qunit"] - path = test/qunit - url = https://github.com/jquery/qunit.git -[submodule "src/plugins"] - path = src/plugins - url = https://github.com/meltingice/CamanJS-Plugins.git diff --git a/mig/images/lib/CamanJS-4.1.1/.travis.yml b/mig/images/lib/CamanJS-4.1.1/.travis.yml deleted file mode 100644 index c2ba3f90b..000000000 --- a/mig/images/lib/CamanJS-4.1.1/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: node_js -node_js: - - 0.8 \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/Cakefile b/mig/images/lib/CamanJS-4.1.1/Cakefile deleted file mode 100644 index c852ea731..000000000 --- a/mig/images/lib/CamanJS-4.1.1/Cakefile +++ /dev/null @@ -1,193 +0,0 @@ -fs = require 'fs' -{exec} = require 'child_process' -util = require 'util' -#{jsmin} = require 'jsmin' - -try - packer = require 'packer' -catch err - packer = null - -targetName = "caman" - -### -CoffeeScript Options -### -csSrcDir = "src" -csTargetDir = "dist" - -targetCoffee = "#{csTargetDir}/caman" - -targetCoreJS = "#{csTargetDir}/#{targetName}.js" -targetCoreMinJS = "#{csTargetDir}/#{targetName}.min.js" -targetCorePackJS = "#{csTargetDir}/#{targetName}.pack.js" -coffeeCoreOpts = "-j #{targetName}.js -o #{csTargetDir}" - -targetFullJS = "#{csTargetDir}/#{targetName}.full.js" -targetFullMinJS = "#{csTargetDir}/#{targetName}.full.min.js" -targetFullPackJS = "#{csTargetDir}/#{targetName}.full.pack.js" -coffeeFullOpts = "-j #{targetName}.full.js -o #{csTargetDir}" - -# All source files listed in include order -coffeeFiles = [ - "core/util" - - # Core library - "core/caman" - - # Everything else - "core/analyze" - "core/autoload" - "core/blender" - "core/calculate" - "core/convert" - "core/event" - "core/filter" - "core/io" - "core/layer" - "core/logger" - "core/pixelinfo" - "core/plugin" - "core/renderer" - "core/store" - - # Non-core files - "lib/blenders" - "lib/filters" - "lib/size" -] - -pluginsFolder = "src/plugins/src" - -### -Event System -### -finishedCallback = {} -finished = (type) -> - finishedCallback[type]() if finishedCallback[type]? - -finishListener = (type, cb) -> - finishedCallback[type] = cb - -getPlugins = -> - content = "" - - util.log "Gathering plugin files in #{pluginsFolder}" - pluginFiles = fs.readdirSync pluginsFolder - - util.log "Discovered #{pluginFiles.length} plugins" - for plugin in pluginFiles - continue if fs.statSync("#{pluginsFolder}/#{plugin}").isDirectory() - content += fs.readFileSync("#{pluginsFolder}/#{plugin}", "utf8") + "\n\n" - - return content - -### -Tasks -### -task 'docs', 'Generates documentation for the coffee files', -> - util.log 'Invoking docco on the CoffeeScript source files' - - files = coffeeFiles - files[i] = "src/#{files[i]}.coffee" for i in [0...files.length] - - pluginFiles = fs.readdirSync pluginsFolder - for plugin in pluginFiles - continue if fs.statSync("#{pluginsFolder}/#{plugin}").isDirectory() - files.push "#{pluginsFolder}/#{plugin}" - - exec "node_modules/docco/bin/docco -l parallel #{files.join(' ')}", (err, stdout, stderr) -> - util.log err if err - util.log "Documentation built into docs/ folder." - -task 'watch', 'Automatically recompile the CoffeeScript files when updated', -> - util.log "Watching for changes in #{csSrcDir}" - - for jsFile in coffeeFiles then do (jsFile) -> - fs.watchFile "#{csSrcDir}/#{jsFile}.coffee", (curr, prev) -> - if +curr.mtime isnt +prev.mtime - util.log "#{csSrcDir}/#{jsFile}.coffee updated" - invoke 'build' - -task 'build', 'Compile and minify all CoffeeScript source files', -> - finishListener 'js', -> invoke 'minify' - invoke 'compile' - -option '-m', '--map', 'Compile with source maps' -task 'compile', 'Compile all CoffeeScript source files', (options) -> - util.log "Building #{targetCoreJS} and #{targetFullJS}" - contents = [] - remaining = coffeeFiles.length - - util.log "Appending #{coffeeFiles.length} files to #{targetCoffee}.coffee" - - for file, index in coffeeFiles then do (file, index) -> - fs.readFile "#{csSrcDir}/#{file}.coffee", "utf8", (err, fileContents) -> - util.log err if err - - contents[index] = fileContents - util.log "[#{index + 1}] #{file}.coffee" - process() if --remaining is 0 - - process = -> - core = contents.join("\n\n") - full = core + "\n\n" + getPlugins() - - if options.map - util.log "Source map support enabled" - coreOpts = "#{coffeeCoreOpts} -m #{targetCoffee}.coffee" - fullOpts = "#{coffeeFullOpts} -m #{targetCoffee}.full.coffee" - else - coreOpts = "#{coffeeCoreOpts} -c #{targetCoffee}.coffee" - fullOpts = "#{coffeeFullOpts} -c #{targetCoffee}.full.coffee" - - fs.writeFile "#{targetCoffee}.coffee", core, "utf8", (err) -> - util.log err if err - - exec "coffee #{coreOpts}", (err, stdout, stderr) -> - util.log err if err - util.log "Compiled #{targetCoreJS}" - - if options.map - map = JSON.parse fs.readFileSync("#{targetCoffee}.map") - map.sources = ["caman.coffee"] - fs.writeFileSync "#{targetCoffee}.map", JSON.stringify(map) - - fs.writeFile "#{targetCoffee}.full.coffee", full, "utf8", (err) -> - util.log err if err - - exec "coffee #{fullOpts}", (err, stdout, stderr) -> - util.log err if err - util.log "Compiled #{targetFullJS}" - - if options.map - map = JSON.parse fs.readFileSync("#{targetCoffee}.full.map") - map.sources = ["caman.full.coffee"] - fs.writeFileSync "#{targetCoffee}.full.map", JSON.stringify(map) - - # if not err - # fs.unlink "#{targetCoffee}.full.coffee", (err) -> util.log err if err - - finished('js') - - -task 'minify', 'Minify the CoffeeScript files', -> - util.log "Minifying #{targetCoreJS}" - fs.readFile targetCoreJS, "utf8", (err, contents) -> - fs.writeFile targetCoreMinJS, jsmin(contents), "utf8", (err) -> - util.log err if err - - if packer - util.log "Packing #{targetCoreJS}" - fs.writeFile targetCorePackJS, packer.pack(contents, true), "utf8", (err) -> - util.log err if err - - util.log "Minifying #{targetFullJS}" - fs.readFile targetFullJS, "utf8", (err, contents) -> - fs.writeFile targetFullMinJS, jsmin(contents), "utf8", (err) -> - util.log err if err - - if packer - util.log "Packing #{targetFullJS}" - fs.writeFile targetFullPackJS, packer.pack(contents, true), "utf8", (err) -> - util.log err if err diff --git a/mig/images/lib/CamanJS-4.1.1/LICENSE b/mig/images/lib/CamanJS-4.1.1/LICENSE deleted file mode 100644 index c1faabd2a..000000000 --- a/mig/images/lib/CamanJS-4.1.1/LICENSE +++ /dev/null @@ -1,10 +0,0 @@ -Copyright (c) 2010, Ryan LeFevre -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Ryan LeFevre nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/README.md b/mig/images/lib/CamanJS-4.1.1/README.md deleted file mode 100644 index efa4cc22a..000000000 --- a/mig/images/lib/CamanJS-4.1.1/README.md +++ /dev/null @@ -1,134 +0,0 @@ -# About the Project - -[![Build Status](https://secure.travis-ci.org/meltingice/CamanJS.png)](http://travis-ci.org/meltingice/CamanJS) - -The main focus of CamanJS is manipulating images using the HTML5 canvas and Javascript. It's a combination of a simple-to-use interface with advanced and efficient image/canvas editing techniques. It is also completely library independent and can be safely used next to jQuery, YUI, Scriptaculous, MooTools, etc. - -CamanJS is very easy to extend with new filters and plugins, and it comes with a wide array of image editing functionality, which is only growing as the community makes more plugins. All features that are not a part of the core CamanJS library are in a [separate plugins repository](https://github.com/meltingice/CamanJS-Plugins). - -For more information, I highly recommend taking a look at the [official website](http://camanjs.com) where there is more comprehensive documentation and interactive demos. You can also [read the wiki](https://github.com/meltingice/CamanJS/wiki) for some basic information about the project and how to use it. - -CamanJS is written in [Coffeescript](http://coffeescript.org) as of version 3.0. **It works both in-browser and in NodeJS.** - -## Usage - -Include one of the versions in the `dist/` folder, then you can run: - -```js -Caman("#image-id", function () { - this.brightness(10); - this.contrast(20); - this.render(function () { - alert("Done!"); - }); -}); -``` - -Caman also supports modifying images via the `data-caman` HTML attribute. Simply separate each instruction with a space. Images with the `data-caman` attribute will automatically be modified at page load. - -```html - -``` - -### HiDPI Support - -Version 4 introduces better support for HiDPI (Retina) displays. It allows you to specify a higher resolution replacement using HTML data attributes. Keep in mind, however, that higher resolution images take longer to render. - -**HTML data attributes** - -* `data-caman-hidpi`: URL to the high resolution replacement image -* `data-caman-hidpi-disabled`: HiDPI support is enabled by default, so add this attribute if you wish to force disable it - -## Upgrading to Version 4 - -There is only 1 breaking change that occured with the version 4 release. When you initialize CamanJS with a canvas and an image, the parameter order has changed. It is now: - -``` javascript -Caman("#canvas-id", "/path/to/image.png", function() {}); -``` - -This is in order to be more consistent with initialization, such that the "initialization object" is always the first parameter. Update your code accordingly. - -## Development - -If you are a developer who is contributing directly to the project, there are some tools to help you out. - -### Building - -To install all dependencies required for development, run `npm install -d`. - -Because all plugins are in a separate repository, make sure you run: - -``` -git submodule init && git submodule update -``` - -To build, simply run `cake build`. The resulting files will be placed in the dist/ folder. Plugins will be automatically discovered and added to caman.full.js after the core library. You can also auto-compile when a file changes by using `cake watch`. - -If you add any files to the core library, you will need to add them to the `coffeeFiles` array in the Cakefile. The point of this is so that order is preserved when generating the file JS file. Plugins do not need to be added to the Cakefile. - -You will probably want to generate documentation if you make any changes. In addition to the normal requirements, you will also need the Python library Pygments. - -To generate the documentation, run `cake docs`. - -## CDN JS Hosting - -CamanJS is hosted on CDN JS if you're looking for a CDN hosting solution. It is the full and minified version of the library, which means all plugins are included. Simply load CamanJS directly from [this URL](http://cdnjs.cloudflare.com/ajax/libs/camanjs/3.3.0/caman.full.min.js) for usage on your site. - -## NodeJS Compatibility - -CamanJS is fully compatible with NodeJS. The easiest way to install it is: - -``` -npm install caman -``` - -**Saving from NodeJS** - -To save your modified image in NodeJS, simply call the save() function **after** rendering is finished by passing a callback function to `render()`. Trying to save before rendering is finished will cause issues. - -``` coffeescript -Caman "./path/to/file.jpg", -> - @brightness 40 - @render -> @save "./output.jpg" -``` - -## Testing - -Tests for CamanJS run both in NodeJS and the browser. - -### NodeJS - -The NodeJS tests use mocha as the test runner. The simplest way to run the test suite is: - -``` -npm test -``` - -### Browser - -The browser tests are run by Testacular. It will start up Chrome, Firefox, and Safari in the background. If you're running Windows, you will want to remove Safari by editing `test/testacular.conf.js`. You can minimize each of these browsers if desired. It will automatically run tests after CamanJS is recompiled by the Cakefile as well. - -**Because it prefers to be installed globally, Testacular is a soft dependency.** - -**Install** -``` -npm install -g testacular -``` - -**Run** -``` -testacular start test/testacular.conf.js -``` - -# Project Contributors - -* [Ryan LeFevre](http://twitter.com/meltingice) - Project Creator, Maintainer, and Lead Developer -* [Rick Waldron](http://twitter.com/rwaldron) - Plugin Architect and Developer -* [Cezar Sá Espinola](http://twitter.com/cezarsa) - Developer -* [Jarques Pretorius](http://twitter.com/jarques) - Logo Designer - -# Plugin Contributors - -* [Hosselaer](https://github.com/Hosselaer) -* [Mario Klingemann](http://www.quasimondo.com) diff --git a/mig/images/lib/CamanJS-4.1.1/adapters/jquery.js b/mig/images/lib/CamanJS-4.1.1/adapters/jquery.js deleted file mode 100644 index fa940a85e..000000000 --- a/mig/images/lib/CamanJS-4.1.1/adapters/jquery.js +++ /dev/null @@ -1,10 +0,0 @@ -/* - * jQuery plugin adapter for CamanJS - */ -if (window.jQuery) { - window.jQuery.fn.caman = function (callback) { - return this.each(function () { - Caman(this, callback); - }); - }; -} \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/component.json b/mig/images/lib/CamanJS-4.1.1/component.json deleted file mode 100644 index b542039d0..000000000 --- a/mig/images/lib/CamanJS-4.1.1/component.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "caman", - "version": "4.1.1", - "main": ["./dist/caman.min.js", "./dist/caman.full.min.js"], - "dependencies": { - } -} \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/dist/caman.coffee b/mig/images/lib/CamanJS-4.1.1/dist/caman.coffee deleted file mode 100644 index fad8ac8eb..000000000 --- a/mig/images/lib/CamanJS-4.1.1/dist/caman.coffee +++ /dev/null @@ -1,2260 +0,0 @@ -# Look what you make me do Javascript -slice = Array::slice - -# DOM simplifier (no jQuery dependency) -# NodeJS compatible -$ = (sel, root = document) -> - return sel if typeof sel is "object" or exports? - root.querySelector sel - -class Util - # Unique value utility - @uniqid = do -> - id = 0 - get: -> id++ - - # Helper function that extends one object with all the properies of other objects - @extend = (obj) -> - dest = obj - src = slice.call arguments, 1 - - for copy in src - for own prop of copy - dest[prop] = copy[prop] - - return dest - - # In order to stay true to the latest spec, RGB values must be clamped between - # 0 and 255. If we don't do this, weird things happen. - @clampRGB = (val) -> - return 0 if val < 0 - return 255 if val > 255 - val - - @copyAttributes: (from, to, opts={}) -> - for attr in from.attributes - continue if opts.except? and attr.nodeName in opts.except - to.setAttribute(attr.nodeName, attr.nodeValue) - - # Support for browsers that don't know Uint8Array (such as IE9) - @dataArray: (length = 0) -> - return new Uint8Array(length) if Caman.NodeJS or window.Uint8Array? - return new Array(length) - -# NodeJS compatibility -if exports? - Root = exports - Canvas = require 'canvas' - Image = Canvas.Image - - Fiber = require 'fibers' - - fs = require 'fs' -else - Root = window - -# Here it begins. Caman is defined. -# There are many different initialization for Caman, which are described on the -# [Basic Usage](http://camanjs.com/docs) page. -# -# Initialization is tricky because we need to make sure everything we need is actually fully -# loaded in the DOM before proceeding. When initialized on an image, we need to make sure that the -# image is done loading before converting it to a canvas element and writing the pixel data. If we -# do this prematurely, the browser will throw a DOM Error, and chaos will ensue. In the event that -# we initialize Caman on a canvas element while specifying an image URL, we need to create a new -# image element, load the image, then continue with initialization. -# -# The main goal for Caman was simplicity, so all of this is handled transparently to the end-user. -Root.Caman = class Caman - @version: - release: "4.1.1" - date: "4/8/2013" - - # Debug mode enables console logging - @DEBUG: false - - # Are we in a NodeJS environment? - @NodeJS: exports? - - # Should we check the DOM for images with Caman instructions? - @autoload: not Caman.NodeJS - - # Allow reverting the canvas? - # If your JS process is running out of memory, disabling - # this could help drastically. - @allowRevert: true - - # Default cross-origin policy - @crossOrigin: "anonymous" - - @toString: -> - "Version " + Caman.version.release + ", Released " + Caman.version.date; - - # Set the URL of the image proxy script - @remoteProxy: "" - - # Change the GET param used with the proxy script if needed - @proxyParam: "camanProxyUrl" - - @getAttrId: (canvas) -> - return true if Caman.NodeJS - - if typeof canvas is "string" - canvas = $(canvas) - - return null unless canvas? and canvas.getAttribute? - canvas.getAttribute 'data-caman-id' - - constructor: -> - throw "Invalid arguments" if arguments.length is 0 - - if @ instanceof Caman - # We have to do this to avoid polluting the global scope - # because of how Coffeescript binds functions specified - # with => and the fact that Caman can be invoked as both - # a function and as a 'new' object. - @finishInit = @finishInit.bind(@) - @imageLoaded = @imageLoaded.bind(@) - - args = arguments[0] - - unless Caman.NodeJS - id = parseInt Caman.getAttrId(args[0]), 10 - callback = if typeof args[1] is "function" - args[1] - else if typeof args[2] is "function" - args[2] - else - -> - - if !isNaN(id) and Store.has(id) - return Store.execute(id, callback) - - # Every instance gets a unique ID. Makes it much simpler to check if two variables are the - # same instance. - @id = Util.uniqid.get() - - @initializedPixelData = @originalPixelData = null - @cropCoordinates = x: 0, y: 0 - @cropped = false - @resized = false - - @pixelStack = [] # Stores the pixel layers - @layerStack = [] # Stores all of the layers waiting to be rendered - @canvasQueue = [] # Stores all of the canvases to be processed - @currentLayer = null - @scaled = false - - @analyze = new Analyze @ - @renderer = new Renderer @ - - @domIsLoaded => - @parseArguments(args) - @setup() - - return @ - else - return new Caman(arguments) - - domIsLoaded: (cb) -> - if Caman.NodeJS - setTimeout => - cb.call(@) - , 0 - else - if document.readyState is "complete" - Log.debug "DOM initialized" - setTimeout => - cb.call(@) - , 0 - else - listener = => - if document.readyState is "complete" - Log.debug "DOM initialized" - cb.call(@) - - document.addEventListener "readystatechange", listener, false - - # All possible combinations: - # - # **1 argument** - # - Image selector - # - Image object - # - Canvas selector - # - Canvas object - # - # **2 arguments** - # - Image selector + callback - # - Image object + callback - # - Canvas selector + URL - # - Canvas object + URL - # - # **3 arguments** - # - Canvas selector + URL + callback - # - Canvas object + URL + callback - # - # **NodeJS** - # - file path - # - file object - # - file path + callback - # - file object + callback - parseArguments: (args) -> - throw "Invalid arguments given" if args.length is 0 - - # Defaults - @initObj = null - @initType = null - @imageUrl = null - @callback = -> - - # First argument is always our canvas/image - @setInitObject args[0] - return if args.length is 1 - - switch typeof args[1] - when "string" then @imageUrl = args[1] - when "function" then @callback = args[1] - - return if args.length is 2 - - @callback = args[2] - - if args.length is 4 - @options[key] = val for own key, val of args[4] - - setInitObject: (obj) -> - if Caman.NodeJS - @initObj = obj - @initType = 'node' - return - - if typeof obj is "object" - @initObj = obj - else - @initObj = $(obj) - - throw "Could not find image or canvas for initialization." unless @initObj? - - @initType = @initObj.nodeName.toLowerCase() - - setup: -> - switch @initType - when "node" then @initNode() - when "img" then @initImage() - when "canvas" then @initCanvas() - - initNode: -> - Log.debug "Initializing for NodeJS" - - @image = new Image() - @image.onload = => - Log.debug "Image loaded. Width = #{@imageWidth()}, Height = #{@imageHeight()}" - @canvas = new Canvas @imageWidth(), @imageHeight() - @finishInit() - - @image.onerror = (err) -> throw err - @image.src = @initObj - - initImage: -> - @image = @initObj - @canvas = document.createElement 'canvas' - @context = @canvas.getContext '2d' - Util.copyAttributes @image, @canvas, except: ['src'] - - @image.parentNode.replaceChild @canvas, @image - - @imageAdjustments() - @waitForImageLoaded() - - initCanvas: -> - @canvas = @initObj - @context = @canvas.getContext '2d' - - if @imageUrl? - @image = document.createElement 'img' - @image.src = @imageUrl - - @imageAdjustments() - @waitForImageLoaded() - else - @finishInit() - - imageAdjustments: -> - if @needsHiDPISwap() - Log.debug @image.src, "->", @hiDPIReplacement() - - @swapped = true - @image.src = @hiDPIReplacement() - - if IO.isRemote(@image) - @image.src = IO.proxyUrl(@image.src) - Log.debug "Remote image detected, using URL = #{@image.src}" - - waitForImageLoaded: -> - if @isImageLoaded() - @imageLoaded() - else - @image.onload = @imageLoaded - - isImageLoaded: -> - return false unless @image.complete - return false if @image.naturalWidth? and @image.naturalWidth is 0 - return true - - # Internet Explorer has issues figuring out image dimensions when they aren't - # explicitly defined apparently. We check the normal width/height properties first, - # but fall back to natural sizes if they are 0. - imageWidth: -> @image.width or @image.naturalWidth - imageHeight: -> @image.height or @image.naturalHeight - - imageLoaded: -> - Log.debug "Image loaded. Width = #{@imageWidth()}, Height = #{@imageHeight()}" - - if @swapped - @canvas.width = @imageWidth() / @hiDPIRatio() - @canvas.height = @imageHeight() / @hiDPIRatio() - else - @canvas.width = @imageWidth() - @canvas.height = @imageHeight() - - @finishInit() - - finishInit: -> - @context = @canvas.getContext '2d' unless @context? - - @originalWidth = @preScaledWidth = @width = @canvas.width - @originalHeight = @preScaledHeight = @height = @canvas.height - - @hiDPIAdjustments() - @assignId() unless @hasId() - - if @image? - @context.drawImage @image, - 0, 0, - @imageWidth(), @imageHeight(), - 0, 0, - @preScaledWidth, @preScaledHeight - - @reloadCanvasData() - - if Caman.allowRevert - @initializedPixelData = Util.dataArray(@pixelData.length) - @originalPixelData = Util.dataArray(@pixelData.length) - - for pixel, i in @pixelData - @initializedPixelData[i] = pixel - @originalPixelData[i] = pixel - - @dimensions = - width: @canvas.width - height: @canvas.height - - Store.put @id, @ - - @callback.call @,@ - - # Reset the callback so re-initialization doesn't - # trigger it again. - @callback = -> - - # If you have a separate context reference to this canvas outside of CamanJS - # and you make a change to the canvas outside of CamanJS, you will have to call - # this function to update our context reference to include those changes. - reloadCanvasData: -> - @imageData = @context.getImageData 0, 0, @canvas.width, @canvas.height - @pixelData = @imageData.data - - resetOriginalPixelData: -> - throw "Revert disabled" unless Caman.allowRevert - - @originalPixelData = Util.dataArray(@pixelData.length) - @originalPixelData.push pixel for pixel in @pixelData - - hasId: -> Caman.getAttrId(@canvas)? - - assignId: -> - return if Caman.NodeJS or @canvas.getAttribute 'data-caman-id' - @canvas.setAttribute 'data-caman-id', @id - - hiDPIDisabled: -> - @canvas.getAttribute('data-caman-hidpi-disabled') isnt null - - hiDPIAdjustments: -> - return if Caman.NodeJS or @hiDPIDisabled() - - ratio = @hiDPIRatio() - - if ratio isnt 1 - Log.debug "HiDPI ratio = #{ratio}" - @scaled = true - - @preScaledWidth = @canvas.width - @preScaledHeight = @canvas.height - - @canvas.width = @preScaledWidth * ratio - @canvas.height = @preScaledHeight * ratio - @canvas.style.width = "#{@preScaledWidth}px" - @canvas.style.height = "#{@preScaledHeight}px" - - @context.scale ratio, ratio - - @width = @originalWidth = @canvas.width - @height = @originalHeight = @canvas.height - - hiDPIRatio: -> - devicePixelRatio = window.devicePixelRatio or 1 - backingStoreRatio = @context.webkitBackingStorePixelRatio or - @context.mozBackingStorePixelRatio or - @context.msBackingStorePixelRatio or - @context.oBackingStorePixelRatio or - @context.backingStorePixelRatio or 1 - - devicePixelRatio / backingStoreRatio - - hiDPICapable: -> window.devicePixelRatio? and window.devicePixelRatio isnt 1 - - needsHiDPISwap: -> - return false if @hiDPIDisabled() or !@hiDPICapable() - @hiDPIReplacement() isnt null - - hiDPIReplacement: -> - return null unless @image? - @image.getAttribute 'data-caman-hidpi' - - replaceCanvas: (newCanvas) -> - oldCanvas = @canvas - @canvas = newCanvas - @context = @canvas.getContext '2d' - - oldCanvas.parentNode.replaceChild @canvas, oldCanvas - - @width = @canvas.width - @height = @canvas.height - - @reloadCanvasData() - - @dimensions = - width: @canvas.width - height: @canvas.height - - # Begins the rendering process - render: (callback = ->) -> - Event.trigger @, "renderStart" - - @renderer.execute => - @context.putImageData @imageData, 0, 0 - callback.call @ - - # Reverts the canvas back to it's original state while - # maintaining any cropped or resized dimensions. - revert: -> - throw "Revert disabled" unless Caman.allowRevert - - @pixelData[i] = pixel for pixel, i in @originalVisiblePixels() - @context.putImageData @imageData, 0, 0 - - # Completely resets the canvas back to it's original state. - # Any size adjustments will also be reset. - reset: -> - canvas = document.createElement('canvas') - Util.copyAttributes(@canvas, canvas) - - canvas.width = @originalWidth - canvas.height = @originalHeight - - ctx = canvas.getContext('2d') - imageData = ctx.getImageData 0, 0, canvas.width, canvas.height - pixelData = imageData.data - - pixelData[i] = pixel for pixel, i in @initializedPixelData - - ctx.putImageData imageData, 0, 0 - - @cropCoordinates = x: 0, y: 0 - @resized = false - - @replaceCanvas(canvas) - - # Returns the original pixel data while maintaining any - # cropping or resizing that may have occured. - originalVisiblePixels: -> - throw "Revert disabled" unless Caman.allowRevert - - pixels = [] - - startX = @cropCoordinates.x - endX = startX + @width - startY = @cropCoordinates.y - endY = startY + @height - - if @resized - canvas = document.createElement('canvas') - canvas.width = @originalWidth - canvas.height = @originalHeight - - ctx = canvas.getContext('2d') - imageData = ctx.getImageData 0, 0, canvas.width, canvas.height - pixelData = imageData.data - - pixelData[i] = pixel for pixel, i in @originalPixelData - - ctx.putImageData imageData, 0, 0 - - scaledCanvas = document.createElement('canvas') - scaledCanvas.width = @width - scaledCanvas.height = @height - - ctx = scaledCanvas.getContext('2d') - ctx.drawImage canvas, 0, 0, @originalWidth, @originalHeight, 0, 0, @width, @height - - pixelData = ctx.getImageData(0, 0, @width, @height).data - width = @width - else - pixelData = @originalPixelData - width = @originalWidth - - for i in [0...pixelData.length] by 4 - coord = PixelInfo.locationToCoordinates(i, width) - if (startX <= coord.x < endX) and (startY <= coord.y < endY) - pixels.push pixelData[i], - pixelData[i+1], - pixelData[i+2], - pixelData[i+3] - - pixels - - # Pushes the filter callback that modifies the RGBA object into the - # render queue - process: (name, processFn) -> - @renderer.add - type: Filter.Type.Single - name: name - processFn: processFn - - return @ - - # Pushes the kernel into the render queue - processKernel: (name, adjust, divisor, bias) -> - if not divisor - divisor = 0 - divisor += adjust[i] for i in [0...adjust.length] - - @renderer.add - type: Filter.Type.Kernel - name: name - adjust: adjust - divisor: divisor - bias: bias or 0 - - return @ - - # Adds a standalone plugin into the render queue - processPlugin: (plugin, args) -> - @renderer.add - type: Filter.Type.Plugin - plugin: plugin - args: args - - return @ - - # Pushes a new layer operation into the render queue and calls the layer - # callback - newLayer: (callback) -> - layer = new Layer @ - @canvasQueue.push layer - @renderer.add type: Filter.Type.LayerDequeue - - callback.call layer - - @renderer.add type: Filter.Type.LayerFinished - return @ - - # Pushes the layer context and moves to the next operation - executeLayer: (layer) -> @pushContext layer - - # Set all of the relevant data to the new layer - pushContext: (layer) -> - @layerStack.push @currentLayer - @pixelStack.push @pixelData - @currentLayer = layer - @pixelData = layer.pixelData - - # Restore the previous layer context - popContext: -> - @pixelData = @pixelStack.pop() - @currentLayer = @layerStack.pop() - - # Applies the current layer to its parent layer - applyCurrentLayer: -> @currentLayer.applyToParent() - - -class Analyze - constructor: (@c) -> - - calculateLevels: -> - levels = - r: {} - g: {} - b: {} - - # Initialize all values to 0 first so there are no data gaps - for i in [0..255] - levels.r[i] = 0 - levels.g[i] = 0 - levels.b[i] = 0 - - # Iterate through each pixel block and increment the level counters - for i in [0...@c.pixelData.length] by 4 - levels.r[@c.pixelData[i]]++ - levels.g[@c.pixelData[i+1]]++ - levels.b[@c.pixelData[i+2]]++ - - # Normalize all of the numbers by converting them to percentages between - # 0 and 1.0 - numPixels = @c.pixelData.length / 4 - - for i in [0..255] - levels.r[i] /= numPixels - levels.g[i] /= numPixels - levels.b[i] /= numPixels - - levels - -Caman.DOMUpdated = -> - imgs = document.querySelectorAll("img[data-caman]") - return unless imgs.length > 0 - - for img in imgs - parser = new CamanParser img, -> - @parse() - @execute() - -# If enabled, we check the page to see if there are any -# images with Caman instructions provided using HTML5 -# data attributes. -if Caman.autoload then do -> - if document.readyState is "complete" - Caman.DOMUpdated() - else - document.addEventListener "DOMContentLoaded", Caman.DOMUpdated, false - -# Parses Caman instructions embedded in the HTML data-caman attribute -class CamanParser - INST_REGEX = "(\\w+)\\((.*?)\\)" - - constructor: (ele, ready) -> - @dataStr = ele.getAttribute('data-caman') - @caman = Caman ele, ready.bind(@) - - parse: -> - @ele = @caman.canvas - - # First we find each instruction as a whole using a global - # regex search. - r = new RegExp(INST_REGEX, 'g') - unparsedInstructions = @dataStr.match r - return unless unparsedInstructions.length > 0 - - # Once we gather all the instructions, we go through each one - # and parse out the filter name + it's parameters. - r = new RegExp(INST_REGEX) - for inst in unparsedInstructions - [m, filter, args] = inst.match(r) - - # Create a factory function so we can catch any errors that - # are produced when running the filters. This also makes it very - # simple to support multiple/complex filter arguments. - instFunc = new Function("return function() { - this.#{filter}(#{args}); - };") - - try - func = instFunc() - func.call @caman - catch e - Log.debug e - - execute: -> - ele = @ele - @caman.render -> - ele.parentNode.replaceChild @toImage(), ele - -# Built-in layer blenders. Many of these mimic Photoshop blend modes. -Caman.Blender = class Blender - @blenders = {} - - # Registers a blender. Can be used to add your own blenders outside of - # the core library, if needed. - @register: (name, func) -> @blenders[name] = func - - # Executes a blender to combine a layer with its parent. - @execute: (name, rgbaLayer, rgbaParent) -> - @blenders[name](rgbaLayer, rgbaParent) - -# Various math-heavy helpers -Caman.Calculate = class Calculate - # Calculates the distance between two points - @distance: (x1, y1, x2, y2) -> - Math.sqrt Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) - - # Generates a pseudorandom number that lies within the max - mix range. The number can be either - # an integer or a float depending on what the user specifies. - @randomRange: (min, max, getFloat = false) -> - rand = min + (Math.random() * (max - min)) - return if getFloat then rand.toFixed(getFloat) else Math.round(rand) - - # Calculates the luminance of a single pixel using a special weighted sum - @luminance: (rgba) -> (0.299 * rgba.r) + (0.587 * rgba.g) + (0.114 * rgba.b) - - # Generates a bezier curve given a start and end point, with two control points in between. - # Can also optionally bound the y values between a low and high bound. - # - # This is different than most bezier curve functions because it attempts to construct it in such - # a way that we can use it more like a simple input -> output system, or a one-to-one function. - # In other words we can provide an input color value, and immediately receive an output modified - # color value. - # - # Note that, by design, this does not force X values to be in the range [0..255]. This is to - # generalize the function a bit more. If you give it a starting X value that isn't 0, and/or a - # ending X value that isn't 255, you may run into problems with your filter! - @bezier: (start, ctrl1, ctrl2, end, lowBound, highBound) -> - x0 = start[0] - y0 = start[1] - x1 = ctrl1[0] - y1 = ctrl1[1] - x2 = ctrl2[0] - y2 = ctrl2[1] - x3 = end[0] - y3 = end[1] - bezier = {} - - # Calculate our X/Y coefficients - Cx = parseInt(3 * (x1 - x0), 10) - Bx = 3 * (x2 - x1) - Cx - Ax = x3 - x0 - Cx - Bx - - Cy = 3 * (y1 - y0) - By = 3 * (y2 - y1) - Cy - Ay = y3 - y0 - Cy - By - - # 1000 is actually arbitrary. We need to make sure we do enough - # calculations between 0 and 255 that, in even the more extreme - # circumstances, we calculate as many values as possible. In the event - # that an X value is skipped, it will be found later on using linear - # interpolation. - for i in [0...1000] - t = i / 1000 - - curveX = Math.round (Ax * Math.pow(t, 3)) + (Bx * Math.pow(t, 2)) + (Cx * t) + x0 - curveY = Math.round (Ay * Math.pow(t, 3)) + (By * Math.pow(t, 2)) + (Cy * t) + y0 - - if lowBound and curveY < lowBound - curveY = lowBound - else if highBound and curveY > highBound - curveY = highBound - - bezier[curveX] = curveY - - # Do a search for missing values in the bezier array and use linear - # interpolation to approximate their values - if bezier.length < end[0] + 1 - for i in [0..end[0]] - if not bezier[i]? - leftCoord = [i-1, bezier[i-1]] - - # Find the first value to the right. Ideally this loop will break - # very quickly. - for j in [i..end[0]] - if bezier[j]? - rightCoord = [j, bezier[j]] - break - - bezier[i] = leftCoord[1] + - ((rightCoord[1] - leftCoord[1]) / (rightCoord[0] - leftCoord[0])) * - (i - leftCoord[0]) - - # Edge case - bezier[end[0]] = bezier[end[0] - 1] if not bezier[end[0]]? - - return bezier - - -# Tons of color conversion functions -class Convert - # Converts the hex representation of a color to RGB values. - # Hex value can optionally start with the hash (#). - # - #
-  # @param   String  hex   The colors hex value
-  # @return  Array         The RGB representation
-  # 
- @hexToRGB: (hex) -> - hex = hex.substr(1) if hex.charAt(0) is "#" - r = parseInt hex.substr(0, 2), 16 - g = parseInt hex.substr(2, 2), 16 - b = parseInt hex.substr(4, 2), 16 - - r: r, g: g, b: b - - # Converts an RGB color to HSL. - # Assumes r, g, and b are in the set [0, 255] and - # returns h, s, and l in the set [0, 1]. - # - #
-  # @param   Number  r   Red channel
-  # @param   Number  g   Green channel
-  # @param   Number  b   Blue channel
-  # @return              The HSL representation
-  # 
- @rgbToHSL: (r, g, b) -> - if typeof r is "object" - g = r.g - b = r.b - r = r.r - - r /= 255 - g /= 255 - b /= 255 - - max = Math.max r, g, b - min = Math.min r, g, b - l = (max + min) / 2 - - if max is min - h = s = 0 - else - d = max - min - s = if l > 0.5 then d / (2 - max - min) else d / (max + min) - h = switch max - when r then (g - b) / d + (if g < b then 6 else 0) - when g then (b - r) / d + 2 - when b then (r - g) / d + 4 - - h /= 6 - - h: h, s: s, l: l - - # Converts an HSL color value to RGB. Conversion formula - # adapted from http://en.wikipedia.org/wiki/HSL_color_space. - # Assumes h, s, and l are contained in the set [0, 1] and - # returns r, g, and b in the set [0, 255]. - # - #
-  # @param   Number  h       The hue
-  # @param   Number  s       The saturation
-  # @param   Number  l       The lightness
-  # @return  Array           The RGB representation
-  # 
- @hslToRGB: (h, s, l) -> - if typeof h is "object" - s = h.s - l = h.l - h = h.h - - if s is 0 - r = g = b = l - else - q = if l < 0.5 then l * (1 + s) else l + s - l * s - p = 2 * l - q - - r = @hueToRGB p, q, h + 1/3 - g = @hueToRGB p, q, h - b = @hueToRGB p, q, h - 1/3 - - r: r * 255, g: g * 255, b: b * 255 - - # Converts from the hue color space back to RGB - @hueToRGB: (p, q, t) -> - if t < 0 then t += 1 - if t > 1 then t -= 1 - if t < 1/6 then return p + (q - p) * 6 * t - if t < 1/2 then return q - if t < 2/3 then return p + (q - p) * (2/3 - t) * 6 - return p - - # Converts an RGB color value to HSV. Conversion formula - # adapted from http://en.wikipedia.org/wiki/HSV_color_space. - # Assumes r, g, and b are contained in the set [0, 255] and - # returns h, s, and v in the set [0, 1]. - # - #
-  # @param   Number  r       The red color value
-  # @param   Number  g       The green color value
-  # @param   Number  b       The blue color value
-  # @return  Array           The HSV representation
-  # 
- @rgbToHSV: (r, g, b) -> - r /= 255 - g /= 255 - b /= 255 - - max = Math.max r, g, b - min = Math.min r, g, b - v = max - d = max - min - - s = if max is 0 then 0 else d / max - - if max is min - h = 0 - else - h = switch max - when r then (g - b) / d + (if g < b then 6 else 0) - when g then (b - r) / d + 2 - when b then (r - g) / d + 4 - - h /= 6 - - h: h, s: s, v: v - - # Converts an HSV color value to RGB. Conversion formula - # adapted from http://en.wikipedia.org/wiki/HSV_color_space. - # Assumes h, s, and v are contained in the set [0, 1] and - # returns r, g, and b in the set [0, 255]. - # - #
-  # @param   Number  h       The hue
-  # @param   Number  s       The saturation
-  # @param   Number  v       The value
-  # @return  Array           The RGB representation
-  # 
- @hsvToRGB: (h, s, v) -> - i = Math.floor h * 6 - f = h * 6 - i - p = v * (1 - s) - q = v * (1 - f * s) - t = v * (1 - (1 - f) * s) - - switch i % 6 - when 0 - r = v - g = t - b = p - when 1 - r = q - g = v - b = p - when 2 - r = p - g = v - b = t - when 3 - r = p - g = q - b = v - when 4 - r = t - g = p - b = v - when 5 - r = v - g = p - b = q - - r: r * 255, g: g * 255, b: b * 255 - - # Converts a RGB color value to the XYZ color space. Formulas - # are based on http://en.wikipedia.org/wiki/SRGB assuming that - # RGB values are sRGB. - # - # Assumes r, g, and b are contained in the set [0, 255] and - # returns x, y, and z. - # - #
-  # @param   Number  r       The red color value
-  # @param   Number  g       The green color value
-  # @param   Number  b       The blue color value
-  # @return  Array           The XYZ representation
-  # 
- @rgbToXYZ: (r, g, b) -> - r /= 255 - g /= 255 - b /= 255 - - if r > 0.04045 - r = Math.pow((r + 0.055) / 1.055, 2.4) - else - r /= 12.92 - - if g > 0.04045 - g = Math.pow((g + 0.055) / 1.055, 2.4) - else - g /= 12.92 - - if b > 0.04045 - b = Math.pow((b + 0.055) / 1.055, 2.4) - else - b /= 12.92 - - x = r * 0.4124 + g * 0.3576 + b * 0.1805; - y = r * 0.2126 + g * 0.7152 + b * 0.0722; - z = r * 0.0193 + g * 0.1192 + b * 0.9505; - - x: x * 100, y: y * 100, z: z * 100 - - # Converts a XYZ color value to the sRGB color space. Formulas - # are based on http://en.wikipedia.org/wiki/SRGB and the resulting - # RGB value will be in the sRGB color space. - # Assumes x, y and z values are whatever they are and returns - # r, g and b in the set [0, 255]. - # - #
-  # @param   Number  x       The X value
-  # @param   Number  y       The Y value
-  # @param   Number  z       The Z value
-  # @return  Array           The RGB representation
-  # 
- @xyzToRGB: (x, y, z) -> - x /= 100 - y /= 100 - z /= 100 - - r = (3.2406 * x) + (-1.5372 * y) + (-0.4986 * z) - g = (-0.9689 * x) + (1.8758 * y) + (0.0415 * z) - b = (0.0557 * x) + (-0.2040 * y) + (1.0570 * z) - - if r > 0.0031308 - r = (1.055 * Math.pow(r, 0.4166666667)) - 0.055 - else - r *= 12.92 - - if g > 0.0031308 - g = (1.055 * Math.pow(g, 0.4166666667)) - 0.055 - else - g *= 12.92 - - if b > 0.0031308 - b = (1.055 * Math.pow(b, 0.4166666667)) - 0.055 - else - b *= 12.92 - - r: r * 255, g: g * 255, b: b * 255 - - # Converts a XYZ color value to the CIELAB color space. Formulas - # are based on http://en.wikipedia.org/wiki/Lab_color_space - # The reference white point used in the conversion is D65. - # Assumes x, y and z values are whatever they are and returns - # L*, a* and b* values - # - #
-  # @param   Number  x       The X value
-  # @param   Number  y       The Y value
-  # @param   Number  z       The Z value
-  # @return  Array           The Lab representation
-  # 
- @xyzToLab: (x, y, z) -> - if typeof x is "object" - y = x.y - z = x.z - x = x.x - - whiteX = 95.047 - whiteY = 100.0 - whiteZ = 108.883 - - x /= whiteX - y /= whiteY - z /= whiteZ - - if x > 0.008856451679 - x = Math.pow(x, 0.3333333333) - else - x = (7.787037037 * x) + 0.1379310345 - - if y > 0.008856451679 - y = Math.pow(y, 0.3333333333) - else - y = (7.787037037 * y) + 0.1379310345 - - if z > 0.008856451679 - z = Math.pow(z, 0.3333333333) - else - z = (7.787037037 * z) + 0.1379310345 - - l = 116 * y - 16 - a = 500 * (x - y) - b = 200 * (y - z) - - l: l, a: a, b: b - - # Converts a L*, a*, b* color values from the CIELAB color space - # to the XYZ color space. Formulas are based on - # http://en.wikipedia.org/wiki/Lab_color_space - # - # The reference white point used in the conversion is D65. - # Assumes L*, a* and b* values are whatever they are and returns - # x, y and z values. - # - #
-  # @param   Number  l       The L* value
-  # @param   Number  a       The a* value
-  # @param   Number  b       The b* value
-  # @return  Array           The XYZ representation
-  # 
- @labToXYZ: (l, a, b) -> - if typeof l is "object" - a = l.a - b = l.b - l = l.l - - y = (l + 16) / 116 - x = y + (a / 500) - z = y - (b / 200) - - if x > 0.2068965517 - x = x * x * x - else - x = 0.1284185493 * (x - 0.1379310345) - - if y > 0.2068965517 - y = y * y * y - else - y = 0.1284185493 * (y - 0.1379310345) - - if z > 0.2068965517 - z = z * z * z - else - z = 0.1284185493 * (z - 0.1379310345) - - # D65 reference white point - x: x * 95.047, y: y * 100.0, z: z * 108.883 - - @rgbToLab: (r, g, b) -> - if typeof r is "object" - g = r.g - b = r.b - r = r.r - - xyz = @rgbToXYZ(r, g, b) - @xyzToLab xyz - - @labToRGB: (l, a, b) -> - - -# Event system that can be used to register callbacks that get fired -# during certain times in the render process. -class Event - @events = {} - - # All of the supported event types - @types = [ - "processStart" - "processComplete" - "renderStart" - "renderFinished" - "blockStarted" - "blockFinished" - ] - - # Trigger an event - @trigger: (target, type, data) -> - if @events[type] and @events[type].length - for event in @events[type] - if event.target is null or target.id is event.target.id - event.fn.call target, data - - # Listen for an event. Optionally bind the listen to a single CamanInstance - # or all CamanInstances. - @listen: (target, type, fn) -> - # Adjust arguments if target is omitted - if typeof target is "string" - _type = target - _fn = type - - target = null - type = _type - fn = _fn - - # Validation - return false if type not in @types - - @events[type] = [] if not @events[type] - @events[type].push target: target, fn: fn - - return true - -Caman.Event = Event - -# Responsible for storing all of the filters -Caman.Filter = class Filter - # All of the different render operatives - @Type = - Single: 1 - Kernel: 2 - LayerDequeue: 3 - LayerFinished: 4 - LoadOverlay: 5 - Plugin: 6 - - # Registers a filter function - @register: (name, filterFunc) -> Caman::[name] = filterFunc - -# Various I/O based operations -Caman.IO = class IO - @domainRegex = /(?:(?:http|https):\/\/)((?:\w+)\.(?:(?:\w|\.)+))/ - - # Is the given URL remote? - # If a cross-origin setting is set, we assume you have CORS - # properly configured. - @isRemote: (img) -> - return false unless img? - return false if @corsEnabled(img) - return @isURLRemote img.src - - @corsEnabled: (img) -> - img.crossOrigin? and img.crossOrigin.toLowerCase() in ['anonymous', 'use-credentials'] - - @isURLRemote: (url) -> - matches = url.match @domainRegex - return if matches then matches[1] isnt document.domain else false - - @remoteCheck: (src) -> - if @isURLRemote src - if not Caman.remoteProxy.length - Log.info "Attempting to load a remote image without a configured proxy. URL: #{src}" - return - else - if Caman.isURLRemote Caman.remoteProxy - Log.info "Cannot use a remote proxy for loading images." - return - - "#{Caman.remoteProxy}?camanProxyUrl=#{encodeURIComponent(src)}" - - - @proxyUrl: (src) -> - "#{Caman.remoteProxy}?#{Caman.proxyParam}=#{encodeURIComponent(src)}" - - # Shortcut for using one of the bundled proxies. - @useProxy: (lang) -> - langToExt = - ruby: 'rb' - python: 'py' - perl: 'pl' - javascript: 'js' - - lang = lang.toLowerCase() - lang = langToExt[lang] if langToExt[lang]? - "proxies/caman_proxy.#{lang}" - -# Grabs the canvas data, encodes it to Base64, then sets the browser location to -# the encoded data so that the user will be prompted to download it. -Caman::save = -> - if exports? - @nodeSave.apply @, arguments - else - @browserSave.apply @, arguments - -Caman::browserSave = (type = "png") -> - type = type.toLowerCase() - - # Force download (its a bit hackish) - image = @toBase64(type).replace "image/#{type}", "image/octet-stream" - document.location.href = image - -Caman::nodeSave = (file, overwrite = true) -> - try - stats = fs.statSync file - return false if stats.isFile() and not overwrite - catch e - Log.debug "Creating output file #{file}" - - fs.writeFile file, @canvas.toBuffer(), -> - Log.debug "Finished writing to #{file}" - -# Takes the current canvas data, converts it to Base64, then sets it as the source -# of a new Image object and returns it. -Caman::toImage = (type) -> - img = document.createElement 'img' - img.src = @toBase64 type - img.width = @dimensions.width - img.height = @dimensions.height - - if window.devicePixelRatio - img.width /= window.devicePixelRatio - img.height /= window.devicePixelRatio - - return img - -# Base64 encodes the current canvas -Caman::toBase64 = (type = "png") -> - type = type.toLowerCase() - return @canvas.toDataURL "image/#{type}" - - -# The entire layering system for Caman resides in this file. Layers get their own canvasLayer -# objectwhich is created when newLayer() is called. For extensive information regarding the -# specifics of howthe layering system works, there is an in-depth blog post on this very topic. -# Instead of copying the entirety of that post, I'll simply point you towards the -# [blog link](http://blog.meltingice.net/programming/implementing-layers-camanjs). -# -# However, the gist of the layering system is that, for each layer, it creates a new canvas -# element and then either copies the parent layer's data or applies a solid color to the new -# layer. After some (optional) effects are applied, the layer is blended back into the parent -# canvas layer using one of many different blending algorithms. -# -# You can also load an image (local or remote, with a proxy) into a canvas layer, which is useful -# if you want to add textures to an image. -class Layer - constructor: (@c) -> - # Compatibility - @filter = @c - - @options = - blendingMode: 'normal' - opacity: 1.0 - - # Each layer gets its own unique ID - @layerID = Util.uniqid.get() - - # Create the canvas for this layer - @canvas = if exports? then new Canvas() else document.createElement('canvas') - - @canvas.width = @c.dimensions.width - @canvas.height = @c.dimensions.height - - @context = @canvas.getContext('2d') - @context.createImageData @canvas.width, @canvas.height - @imageData = @context.getImageData 0, 0, @canvas.width, @canvas.height - @pixelData = @imageData.data - - # If you want to create nested layers - newLayer: (cb) -> @c.newLayer.call @c, cb - - # Sets the blending mode of this layer. The mode is the name of a blender function. - setBlendingMode: (mode) -> - @options.blendingMode = mode - return @ - - # Sets the opacity of this layer. This affects how much of this layer is applied to the parent - # layer at render time. - opacity: (opacity) -> - @options.opacity = opacity / 100 - return @ - - # Copies the contents of the parent layer to this layer - copyParent: -> - parentData = @c.pixelData - - for i in [0...@c.pixelData.length] by 4 - @pixelData[i] = parentData[i] - @pixelData[i+1] = parentData[i+1] - @pixelData[i+2] = parentData[i+2] - @pixelData[i+3] = parentData[i+3] - - return @ - - # Fills this layer with a single color - fillColor: -> @c.fillColor.apply @c, arguments - - # Loads and overlays an image onto this layer - overlayImage: (image) -> - if typeof image is "object" - image = image.src - else if typeof image is "string" and image[0] is "#" - image = $(image).src - - return @ if not image - - @c.renderer.renderQueue.push - type: Filter.Type.LoadOverlay - src: image - layer: @ - - return @ - - # Takes the contents of this layer and applies them to the parent layer at render time. This - # should never be called explicitly by the user. - applyToParent: -> - parentData = @c.pixelStack[@c.pixelStack.length - 1] - layerData = @c.pixelData - - for i in [0...layerData.length] by 4 - rgbaParent = - r: parentData[i] - g: parentData[i+1] - b: parentData[i+2] - a: parentData[i+3] - - rgbaLayer = - r: layerData[i] - g: layerData[i+1] - b: layerData[i+2] - a: layerData[i+3] - - result = Blender.execute @options.blendingMode, rgbaLayer, rgbaParent - - result.r = Util.clampRGB result.r - result.g = Util.clampRGB result.g - result.b = Util.clampRGB result.b - result.a = rgbaLayer.a if not result.a? - - parentData[i] = rgbaParent.r - ( - (rgbaParent.r - result.r) * (@options.opacity * (result.a / 255)) - ) - parentData[i+1] = rgbaParent.g - ( - (rgbaParent.g - result.g) * (@options.opacity * (result.a / 255)) - ) - parentData[i+2] = rgbaParent.b - ( - (rgbaParent.b - result.b) * (@options.opacity * (result.a / 255)) - ) - - -# Simple console logger class that can be toggled on and off based on Caman.DEBUG -class Logger - constructor: -> - for name in ['log', 'info', 'warn', 'error'] - @[name] = do (name) -> - (args...) -> - return if not Caman.DEBUG - try - console[name].apply console, args - catch e - # We're probably using IE9 or earlier - console[name] args - - @debug = @log - -Log = new Logger() - -# This object is available inside of the process() loop, and it lets filter developers have simple -# access to any arbitrary pixel in the image, as well as information about the current pixel in -# the loop. -class PixelInfo - @coordinatesToLocation: (x, y, width) -> - (y * width + x) * 4 - - @locationToCoordinates: (loc, width) -> - y = Math.floor(loc / (width * 4)) - x = (loc % (width * 4)) / 4 - - return x: x, y: y - - constructor: (@c) -> @loc = 0 - - # Retrieves the X, Y location of the current pixel. The origin is at the bottom left corner of - # the image, like a normal coordinate system. - locationXY: -> - y = @c.dimensions.height - Math.floor(@loc / (@c.dimensions.width * 4)) - x = (@loc % (@c.dimensions.width * 4)) / 4 - - return x: x, y: y - - # Returns an RGBA object for a pixel whose location is specified in relation to the current - # pixel. - getPixelRelative: (horiz, vert) -> - # We invert the vert_offset in order to make the coordinate system non-inverted. In laymans - # terms: -1 means down and +1 means up. - newLoc = @loc + (@c.dimensions.width * 4 * (vert * -1)) + (4 * horiz) - - if newLoc > @c.pixelData.length or newLoc < 0 - return r: 0, g: 0, b: 0, a: 0 - - return { - r: @c.pixelData[newLoc] - g: @c.pixelData[newLoc + 1] - b: @c.pixelData[newLoc + 2] - a: @c.pixelData[newLoc + 3] - } - - # The counterpart to getPixelRelative, this updates the value of a pixel whose location is - # specified in relation to the current pixel. - putPixelRelative: (horiz, vert, rgba) -> - nowLoc = @loc + (@c.dimensions.width * 4 * (vert * -1)) + (4 * horiz) - - return if newLoc > @c.pixelData.length or newLoc < 0 - - @c.pixelData[newLoc] = rgba.r - @c.pixelData[newLoc + 1] = rgba.g - @c.pixelData[newLoc + 2] = rgba.b - @c.pixelData[newLoc + 3] = rgba.a - - return true - - # Gets an RGBA object for an arbitrary pixel in the canvas specified by absolute X, Y coordinates - getPixel: (x, y) -> - loc = @coordinatesToLocation(x, y, @width) - - return { - r: @c.pixelData[loc] - g: @c.pixelData[loc + 1] - b: @c.pixelData[loc + 2] - a: @c.pixelData[loc + 3] - } - - # Updates the pixel at the given X, Y coordinate - putPixel: (x, y, rgba) -> - loc = @coordinatesToLocation(x, y, @width) - - @c.pixelData[loc] = rgba.r - @c.pixelData[loc + 1] = rgba.g - @c.pixelData[loc + 2] = rgba.b - @c.pixelData[loc + 3] = rgba.a - - -# Stores and registers standalone plugins -class Plugin - @plugins = {} - - @register: (name, plugin) -> @plugins[name] = plugin - @execute: (context, name, args) -> @plugins[name].apply context, args - -Caman.Plugin = Plugin - -# Handles all of the various rendering methods in Caman. Most of the image modification happens -# here. A new Renderer object is created for every render operation. -Caman.Renderer = class Renderer - # The number of blocks to split the image into during the render process to simulate - # concurrency. This also helps the browser manage the (possibly) long running render jobs. - @Blocks = if Caman.NodeJS then require('os').cpus().length else 4 - - constructor: (@c) -> - @renderQueue = [] - @modPixelData = null - - add: (job) -> - return unless job? - @renderQueue.push job - - # Grabs the next operation from the render queue and passes it to Renderer - # for execution - processNext: => - # If the queue is empty, fire the finished callback - if @renderQueue.length is 0 - Event.trigger @, "renderFinished" - @finishedFn.call(@c) if @finishedFn? - - return @ - - @currentJob = @renderQueue.shift() - - switch @currentJob.type - when Filter.Type.LayerDequeue - layer = @c.canvasQueue.shift() - @c.executeLayer layer - @processNext() - when Filter.Type.LayerFinished - @c.applyCurrentLayer() - @c.popContext() - @processNext() - when Filter.Type.LoadOverlay - @loadOverlay @currentJob.layer, @currentJob.src - when Filter.Type.Plugin - @executePlugin() - else - @executeFilter() - - execute: (callback) -> - @finishedFn = callback - @modPixelData = Util.dataArray(@c.pixelData.length) - - @processNext() - - eachBlock: (fn) -> - # Prepare all the required render data - @blocksDone = 0 - - n = @c.pixelData.length - blockPixelLength = Math.floor (n / 4) / Renderer.Blocks - blockN = blockPixelLength * 4 - lastBlockN = blockN + ((n / 4) % Renderer.Blocks) * 4 - - for i in [0...Renderer.Blocks] - start = i * blockN - end = start + (if i is Renderer.Blocks - 1 then lastBlockN else blockN) - - if Caman.NodeJS - f = Fiber => fn.call(@, i, start, end) - bnum = f.run() - @blockFinished(bnum) - else - setTimeout do (i, start, end) => - => fn.call(@, i, start, end) - , 0 - - # The core of the image rendering, this function executes the provided filter. - # - # NOTE: this does not write the updated pixel data to the canvas. That happens when all filters - # are finished rendering in order to be as fast as possible. - executeFilter: -> - Event.trigger @c, "processStart", @currentJob - - if @currentJob.type is Filter.Type.Single - @eachBlock @renderBlock - else - @eachBlock @renderKernel - - # Executes a standalone plugin - executePlugin: -> - Log.debug "Executing plugin #{@currentJob.plugin}" - Plugin.execute @c, @currentJob.plugin, @currentJob.args - Log.debug "Plugin #{@currentJob.plugin} finished!" - - @processNext() - - # Renders a single block of the canvas with the current filter function - renderBlock: (bnum, start, end) -> - Log.debug "Block ##{bnum} - Filter: #{@currentJob.name}, Start: #{start}, End: #{end}" - Event.trigger @c, "blockStarted", - blockNum: bnum - totalBlocks: Renderer.Blocks - startPixel: start - endPixel: end - - data = r: 0, g: 0, b: 0, a: 0 - pixelInfo = new PixelInfo @c - - for i in [start...end] by 4 - pixelInfo.loc = i - - data.r = @c.pixelData[i] - data.g = @c.pixelData[i+1] - data.b = @c.pixelData[i+2] - data.a = @c.pixelData[i+3] - - res = @currentJob.processFn.call pixelInfo, data - res.a = data.a if not res.a? - - @c.pixelData[i] = Util.clampRGB res.r - @c.pixelData[i+1] = Util.clampRGB res.g - @c.pixelData[i+2] = Util.clampRGB res.b - @c.pixelData[i+3] = Util.clampRGB res.a - - if Caman.NodeJS - Fiber.yield(bnum) - else - @blockFinished bnum - - # Applies an image kernel to the canvas - renderKernel: (bnum, start, end) -> - name = @currentJob.name - bias = @currentJob.bias - divisor = @currentJob.divisor - n = @c.pixelData.length - - adjust = @currentJob.adjust - adjustSize = Math.sqrt adjust.length - - kernel = [] - - Log.debug "Rendering kernel - Filter: #{@currentJob.name}" - - start = Math.max start, @c.dimensions.width * 4 * ((adjustSize - 1) / 2) - end = Math.min end, n - (@c.dimensions.width * 4 * ((adjustSize - 1) / 2)) - - builder = (adjustSize - 1) / 2 - - pixelInfo = new PixelInfo @c - - for i in [start...end] by 4 - pixelInfo.loc = i - builderIndex = 0 - - for j in [-builder..builder] - for k in [builder..-builder] - pixel = pixelInfo.getPixelRelative j, k - kernel[builderIndex * 3] = pixel.r - kernel[builderIndex * 3 + 1] = pixel.g - kernel[builderIndex * 3 + 2] = pixel.b - - builderIndex++ - - res = @processKernel adjust, kernel, divisor, bias - - @modPixelData[i] = Util.clampRGB(res.r) - @modPixelData[i+1] = Util.clampRGB(res.g) - @modPixelData[i+2] = Util.clampRGB(res.b) - @modPixelData[i+3] = @c.pixelData[i+3] - - if Caman.NodeJS - Fiber.yield(bnum) - else - @blockFinished bnum - - # Called when a single block is finished rendering. Once all blocks are done, we signal that this - # filter is finished rendering and continue to the next step. - blockFinished: (bnum) -> - Log.debug "Block ##{bnum} finished! Filter: #{@currentJob.name}" if bnum >= 0 - @blocksDone++ - - Event.trigger @c, "blockFinished", - blockNum: bnum - blocksFinished: @blocksDone - totalBlocks: Renderer.Blocks - - if @blocksDone is Renderer.Blocks - if @currentJob.type is Filter.Type.Kernel - for i in [0...@c.pixelData.length] - @c.pixelData[i] = @modPixelData[i] - - Log.debug "Filter #{@currentJob.name} finished!" if bnum >=0 - Event.trigger @c, "processComplete", @currentJob - - @processNext() - - # The "filter function" for kernel adjustments. - processKernel: (adjust, kernel, divisor, bias) -> - val = r: 0, g: 0, b: 0 - - for i in [0...adjust.length] - val.r += adjust[i] * kernel[i * 3] - val.g += adjust[i] * kernel[i * 3 + 1] - val.b += adjust[i] * kernel[i * 3 + 2] - - val.r = (val.r / divisor) + bias - val.g = (val.g / divisor) + bias - val.b = (val.b / divisor) + bias - val - - # Loads an image onto the current canvas - loadOverlay: (layer, src) -> - img = document.createElement 'img' - img.onload = => - layer.context.drawImage img, 0, 0, @c.dimensions.width, @c.dimensions.height - layer.imageData = layer.context.getImageData 0, 0, @c.dimensions.width, @c.dimensions.height - layer.pixelData = layer.imageData.data - - @c.pixelData = layer.pixelData - - @processNext() - - proxyUrl = IO.remoteCheck src - img.src = if proxyUrl? then proxyUrl else src - -# Used for storing instances of CamanInstance objects such that, when Caman() is called on an -# already initialized element, it returns that object instead of re-initializing. -Caman.Store = class Store - @items = {} - - @has: (search) -> @items[search]? - @get: (search) -> @items[search] - @put: (name, obj) -> @items[name] = obj - @execute: (search, callback) -> - setTimeout => - callback.call @get(search), @get(search) - , 0 - - return @get(search) - - @flush: (name = false) -> - if name then delete @items[name] else @items = {} - -# Directly apply the child layer's pixels to the parent layer with no special changes -Blender.register "normal", (rgbaLayer, rgbaParent) -> - r: rgbaLayer.r - g: rgbaLayer.g - b: rgbaLayer.b - -# Apply the child to the parent by multiplying the color values. This generally creates contrast. -Blender.register "multiply", (rgbaLayer, rgbaParent) -> - r: (rgbaLayer.r * rgbaParent.r) / 255 - g: (rgbaLayer.g * rgbaParent.g) / 255 - b: (rgbaLayer.b * rgbaParent.b) / 255 - -Blender.register "screen", (rgbaLayer, rgbaParent) -> - r: 255 - (((255 - rgbaLayer.r) * (255 - rgbaParent.r)) / 255) - g: 255 - (((255 - rgbaLayer.g) * (255 - rgbaParent.g)) / 255) - b: 255 - (((255 - rgbaLayer.b) * (255 - rgbaParent.b)) / 255) - - -Blender.register "overlay", (rgbaLayer, rgbaParent) -> - result = {} - result.r = - if rgbaParent.r > 128 - 255 - 2 * (255 - rgbaLayer.r) * (255 - rgbaParent.r) / 255 - else (rgbaParent.r * rgbaLayer.r * 2) / 255 - - result.g = - if rgbaParent.g > 128 - 255 - 2 * (255 - rgbaLayer.g) * (255 - rgbaParent.g) / 255 - else (rgbaParent.g * rgbaLayer.g * 2) / 255 - - result.b = - if rgbaParent.b > 128 - 255 - 2 * (255 - rgbaLayer.b) * (255 - rgbaParent.b) / 255 - else (rgbaParent.b * rgbaLayer.b * 2) / 255 - - result - -Blender.register "difference", (rgbaLayer, rgbaParent) -> - r: rgbaLayer.r - rgbaParent.r - g: rgbaLayer.g - rgbaParent.g - b: rgbaLayer.b - rgbaParent.b - -Blender.register "addition", (rgbaLayer, rgbaParent) -> - r: rgbaParent.r + rgbaLayer.r - g: rgbaParent.g + rgbaLayer.g - b: rgbaParent.b + rgbaLayer.b - -Blender.register "exclusion", (rgbaLayer, rgbaParent) -> - r: 128 - 2 * (rgbaParent.r - 128) * (rgbaLayer.r - 128) / 255 - g: 128 - 2 * (rgbaParent.g - 128) * (rgbaLayer.g - 128) / 255 - b: 128 - 2 * (rgbaParent.b - 128) * (rgbaLayer.b - 128) / 255 - -Blender.register "softLight", (rgbaLayer, rgbaParent) -> - result = {} - - result.r = - if rgbaParent.r > 128 - 255 - ((255 - rgbaParent.r) * (255 - (rgbaLayer.r - 128))) / 255 - else (rgbaParent.r * (rgbaLayer.r + 128)) / 255 - - result.g = - if rgbaParent.g > 128 - 255 - ((255 - rgbaParent.g) * (255 - (rgbaLayer.g - 128))) / 255 - else (rgbaParent.g * (rgbaLayer.g + 128)) / 255 - - result.b = - if rgbaParent.b > 128 - 255 - ((255 - rgbaParent.b) * (255 - (rgbaLayer.b - 128))) / 255 - else (rgbaParent.b * (rgbaLayer.b + 128)) / 255 - - result - -Blender.register "lighten", (rgbaLayer, rgbaParent) -> - r: if rgbaParent.r > rgbaLayer.r then rgbaParent.r else rgbaLayer.r - g: if rgbaParent.g > rgbaLayer.g then rgbaParent.g else rgbaLayer.g - b: if rgbaParent.b > rgbaLayer.b then rgbaParent.b else rgbaLayer.b - -Blender.register "darken", (rgbaLayer, rgbaParent) -> - r: if rgbaParent.r > rgbaLayer.r then rgbaLayer.r else rgbaParent.r - g: if rgbaParent.g > rgbaLayer.g then rgbaLayer.g else rgbaParent.g - b: if rgbaParent.b > rgbaLayer.b then rgbaLayer.b else rgbaParent.b - -# The filters define all of the built-in functionality that comes with Caman (as opposed to being -# provided by a plugin). All of these filters are ratherbasic, but are extremely powerful when -# many are combined. For information on creating plugins, check out the -# [Plugin Creation](http://camanjs.com/docs/plugin-creation) page, and for information on using -# the plugins, check out the [Built-In Functionality](http://camanjs.com/docs/built-in) page. - -# ## Fill Color -# Fills the canvas with a single solid color. -# -# ### Arguments -# Can take either separate R, G, and B values as arguments, or a single hex color value. -Filter.register "fillColor", -> - if arguments.length is 1 - color = Convert.hexToRGB arguments[0] - else - color = - r: arguments[0] - g: arguments[1] - b: arguments[2] - - @process "fillColor", (rgba) -> - rgba.r = color.r - rgba.g = color.g - rgba.b = color.b - rgba.a = 255 - rgba - -# ## Brightness -# Simple brightness adjustment -# -# ### Arguments -# Range is -100 to 100. Values < 0 will darken image while values > 0 will brighten. -Filter.register "brightness", (adjust) -> - adjust = Math.floor 255 * (adjust / 100) - - @process "brightness", (rgba) -> - rgba.r += adjust - rgba.g += adjust - rgba.b += adjust - rgba - -# ## Saturation -# Adjusts the color saturation of the image. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will desaturate the image while values > 0 will saturate it. -# **If you want to completely desaturate the image**, using the greyscale filter is highly -# recommended because it will yield better results. -Filter.register "saturation", (adjust) -> - adjust *= -0.01 - - @process "saturation", (rgba) -> - max = Math.max rgba.r, rgba.g, rgba.b - - rgba.r += (max - rgba.r) * adjust if rgba.r isnt max - rgba.g += (max - rgba.g) * adjust if rgba.g isnt max - rgba.b += (max - rgba.b) * adjust if rgba.b isnt max - rgba - -# ## Vibrance -# Similar to saturation, but adjusts the saturation levels in a slightly smarter, more subtle way. -# Vibrance will attempt to boost colors that are less saturated more and boost already saturated -# colors less, while saturation boosts all colors by the same level. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will desaturate the image while values > 0 will saturate it. -# **If you want to completely desaturate the image**, using the greyscale filter is highly -# recommended because it will yield better results. -Filter.register "vibrance", (adjust) -> - adjust *= -1 - - @process "vibrance", (rgba) -> - max = Math.max rgba.r, rgba.g, rgba.b - avg = (rgba.r + rgba.g + rgba.b) / 3 - amt = ((Math.abs(max - avg) * 2 / 255) * adjust) / 100 - - rgba.r += (max - rgba.r) * amt if rgba.r isnt max - rgba.g += (max - rgba.g) * amt if rgba.g isnt max - rgba.b += (max - rgba.b) * amt if rgba.b isnt max - rgba - -# ## Greyscale -# An improved greyscale function that should make prettier results -# than simply using the saturation filter to remove color. It does so by using factors -# that directly relate to how the human eye perceves color and values. There are -# no arguments, it simply makes the image greyscale with no in-between. -# -# Algorithm adopted from http://www.phpied.com/image-fun/ -Filter.register "greyscale", (adjust) -> - @process "greyscale", (rgba) -> - # Calculate the average value of the 3 color channels - # using the special factors - avg = Calculate.luminance(rgba) - - rgba.r = avg - rgba.g = avg - rgba.b = avg - rgba - -# ## Contrast -# Increases or decreases the color contrast of the image. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will decrease contrast while values > 0 will increase contrast. -# The contrast adjustment values are a bit sensitive. While unrestricted, sane adjustment values -# are usually around 5-10. -Filter.register "contrast", (adjust) -> - adjust = Math.pow((adjust + 100) / 100, 2) - - @process "contrast", (rgba) -> - # Red channel - rgba.r /= 255; - rgba.r -= 0.5; - rgba.r *= adjust; - rgba.r += 0.5; - rgba.r *= 255; - - # Green channel - rgba.g /= 255; - rgba.g -= 0.5; - rgba.g *= adjust; - rgba.g += 0.5; - rgba.g *= 255; - - # Blue channel - rgba.b /= 255; - rgba.b -= 0.5; - rgba.b *= adjust; - rgba.b += 0.5; - rgba.b *= 255; - - rgba - -# ## Hue -# Adjusts the hue of the image. It can be used to shift the colors in an image in a uniform -# fashion. If you are unfamiliar with Hue, I recommend reading this -# [Wikipedia article](http://en.wikipedia.org/wiki/Hue). -# -# ### Arguments -# Range is 0 to 100 -# Sometimes, Hue is expressed in the range of 0 to 360. If that's the terminology you're used to, -# think of 0 to 100 representing the percentage of Hue shift in the 0 to 360 range. -Filter.register "hue", (adjust) -> - @process "hue", (rgba) -> - hsv = Convert.rgbToHSV rgba.r, rgba.g, rgba.b - - h = hsv.h * 100 - h += Math.abs adjust - h = h % 100 - h /= 100 - hsv.h = h - - rgb = Convert.hsvToRGB hsv.h, hsv.s, hsv.v - rgb.a = rgba.a - rgb - -# ## Colorize -# Uniformly shifts the colors in an image towards the given color. The adjustment range is from 0 -# to 100. The higher the value, the closer the colors in the image shift towards the given -# adjustment color. -# -# ### Arguments -# This filter is polymorphic and can take two different sets of arguments. Either a hex color -# string and an adjustment value, or RGB colors and an adjustment value. -Filter.register "colorize", -> - if arguments.length is 2 - rgb = Convert.hexToRGB(arguments[0]) - level = arguments[1] - else if arguments.length is 4 - rgb = - r: arguments[0] - g: arguments[1] - b: arguments[2] - - level = arguments[3] - - @process "colorize", (rgba) -> - rgba.r -= (rgba.r - rgb.r) * (level / 100) - rgba.g -= (rgba.g - rgb.g) * (level / 100) - rgba.b -= (rgba.b - rgb.b) * (level / 100) - rgba - -# ## Invert -# Inverts all colors in the image by subtracting each color channel value from 255. No arguments. -Filter.register "invert", -> - @process "invert", (rgba) -> - rgba.r = 255 - rgba.r - rgba.g = 255 - rgba.g - rgba.b = 255 - rgba.b - rgba - -# ## Sepia -# Applies an adjustable sepia filter to the image. -# -# ### Arguments -# Assumes adjustment is between 0 and 100, which represents how much the sepia filter is applied. -Filter.register "sepia", (adjust = 100) -> - adjust /= 100 - - @process "sepia", (rgba) -> - # All three color channels have special conversion factors that - # define what sepia is. Here we adjust each channel individually, - # with the twist that you can partially apply the sepia filter. - rgba.r = Math.min(255, (rgba.r * (1 - (0.607 * adjust))) + (rgba.g * (0.769 * adjust)) + (rgba.b * (0.189 * adjust))); - rgba.g = Math.min(255, (rgba.r * (0.349 * adjust)) + (rgba.g * (1 - (0.314 * adjust))) + (rgba.b * (0.168 * adjust))); - rgba.b = Math.min(255, (rgba.r * (0.272 * adjust)) + (rgba.g * (0.534 * adjust)) + (rgba.b * (1- (0.869 * adjust)))); - - rgba - -# ## Gamma -# Adjusts the gamma of the image. -# -# ### Arguments -# Range is from 0 to infinity, although sane values are from 0 to 4 or 5. -# Values between 0 and 1 will lessen the contrast while values greater than 1 will increase it. -Filter.register "gamma", (adjust) -> - @process "gamma", (rgba) -> - rgba.r = Math.pow(rgba.r / 255, adjust) * 255 - rgba.g = Math.pow(rgba.g / 255, adjust) * 255 - rgba.b = Math.pow(rgba.b / 255, adjust) * 255 - rgba - -# ## Noise -# Adds noise to the image on a scale from 1 - 100. However, the scale isn't constrained, so you -# can specify a value > 100 if you want a LOT of noise. -Filter.register "noise", (adjust) -> - adjust = Math.abs(adjust) * 2.55 - - @process "noise", (rgba) -> - rand = Calculate.randomRange adjust * -1, adjust - - rgba.r += rand - rgba.g += rand - rgba.b += rand - rgba - -# ## Clip -# Clips a color to max values when it falls outside of the specified range. -# -# ### Arguments -# Supplied value should be between 0 and 100. -Filter.register "clip", (adjust) -> - adjust = Math.abs(adjust) * 2.55 - - @process "clip", (rgba) -> - if rgba.r > 255 - adjust - rgba.r = 255 - else if rgba.r < adjust - rgba.r = 0 - - if rgba.g > 255 - adjust - rgba.g = 255 - else if rgba.g < adjust - rgba.g = 0 - - if rgba.b > 255 - adjust - rgba.b = 255 - else if rgba.b < adjust - rgba.b = 0 - - rgba - -# ## Channels -# Lets you modify the intensity of any combination of red, green, or blue channels individually. -# -# ### Arguments -# Must be given at least one color channel to adjust in order to work. -# Options format (must specify 1 - 3 colors): -#
{
-#   red: 20,
-#   green: -5,
-#   blue: -40
-# }
-Filter.register "channels", (options) -> - return @ if typeof options isnt "object" - - for own chan, value of options - if value is 0 - delete options[chan] - continue - - options[chan] /= 100 - - return @ if options.length is 0 - - @process "channels", (rgba) -> - if options.red? - if options.red > 0 - rgba.r += (255 - rgba.r) * options.red - else - rgba.r -= rgba.r * Math.abs(options.red) - - if options.green? - if options.green > 0 - rgba.g += (255 - rgba.g) * options.green - else - rgba.g -= rgba.g * Math.abs(options.green) - - if options.blue? - if options.blue > 0 - rgba.b += (255 - rgba.b) * options.blue - else - rgba.b -= rgba.b * Math.abs(options.blue) - - rgba - -# ## Curves -# Curves implementation using Bezier curve equation. If you're familiar with the Curves -# functionality in Photoshop, this works in a very similar fashion. -# -# ### Arguments. -#
-#   chan - [r, g, b, rgb]
-#   start - [x, y] (start of curve; 0 - 255)
-#   ctrl1 - [x, y] (control point 1; 0 - 255)
-#   ctrl2 - [x, y] (control point 2; 0 - 255)
-#   end   - [x, y] (end of curve; 0 - 255)
-# 
-# -# The first argument represents the channels you wish to modify with the filter. It can be an -# array of channels or a string (for a single channel). The rest of the arguments are 2-element -# arrays that represent point coordinates. They are specified in the same order as shown in this -# image to the right. The coordinates are in the range of 0 to 255 for both X and Y values. -# -# The x-axis represents the input value for a single channel, while the y-axis represents the -# output value. -Filter.register "curves", (chans, cps...) -> - # If channels are in a string, split to an array - chans = chans.split("") if typeof chans is "string" - chans = ['r', 'g', 'b'] if chans[0] == "v" - - if cps.length < 3 or cps.length > 4 - # might want to give a warning now - throw "Invalid number of arguments to curves filter" - - start = cps[0] - ctrl1 = cps[1] - ctrl2 = if cps.length == 4 then cps[2] else cps[1] - end = cps[cps.length - 1] - - # Generate a bezier curve - bezier = Calculate.bezier start, ctrl1, ctrl2, end, 0, 255 - - # If the curve starts after x = 0, initialize it with a flat line - # until the curve begins. - bezier[i] = start[1] for i in [0...start[0]] if start[0] > 0 - - # ... and the same with the end point - bezier[i] = end[1] for i in [end[0]..255] if end[0] < 255 - - @process "curves", (rgba) -> - # Now that we have the bezier curve, we do a basic hashmap lookup - # to find and replace color values. - rgba[chans[i]] = bezier[rgba[chans[i]]] for i in [0...chans.length] - rgba - -# ## Exposure -# Adjusts the exposure of the image by using the curves function. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will decrease exposure while values > 0 will increase exposure. -Filter.register "exposure", (adjust) -> - p = Math.abs(adjust) / 100 - - ctrl1 = [0, 255 * p] - ctrl2 = [255 - (255 * p), 255] - - if adjust < 0 - ctrl1 = ctrl1.reverse() - ctrl2 = ctrl2.reverse() - - @curves 'rgb', [0, 0], ctrl1, ctrl2, [255, 255] - - - -# Allows us to crop the canvas and produce a new smaller -# canvas. -Caman.Plugin.register "crop", (width, height, x = 0, y = 0) -> - # Create our new canvas element - if exports? - canvas = new Canvas width, height - else - canvas = document.createElement 'canvas' - Util.copyAttributes @canvas, canvas - - canvas.width = width - canvas.height = height - - ctx = canvas.getContext '2d' - - # Perform the cropping by drawing to the new canvas - ctx.drawImage @canvas, x, y, width, height, 0, 0, width, height - - @cropCoordinates = x: x, y: y - - # Update all of the references - @cropped = true - @replaceCanvas canvas - -# Resize the canvas and the image to a new size -Caman.Plugin.register "resize", (newDims = null) -> - # Calculate new size - if newDims is null or (!newDims.width? and !newDims.height?) - Log.error "Invalid or missing dimensions given for resize" - return - - if not newDims.width? - # Calculate width - newDims.width = @canvas.width * newDims.height / @canvas.height - else if not newDims.height? - # Calculate height - newDims.height = @canvas.height * newDims.width / @canvas.width - - if exports? - canvas = new Canvas newDims.width, newDims.height - else - canvas = document.createElement 'canvas' - Util.copyAttributes @canvas, canvas - - canvas.width = newDims.width - canvas.height = newDims.height - - ctx = canvas.getContext '2d' - - ctx.drawImage @canvas, - 0, 0, - @canvas.width, @canvas.height, - 0, 0, - newDims.width, newDims.height - - @resized = true - @replaceCanvas canvas - -Caman.Filter.register "crop", -> - @processPlugin "crop", Array.prototype.slice.call(arguments, 0) - -Caman.Filter.register "resize", -> - @processPlugin "resize", Array.prototype.slice.call(arguments, 0) \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/dist/caman.full.coffee b/mig/images/lib/CamanJS-4.1.1/dist/caman.full.coffee deleted file mode 100644 index 05951d081..000000000 --- a/mig/images/lib/CamanJS-4.1.1/dist/caman.full.coffee +++ /dev/null @@ -1,2369 +0,0 @@ -# Look what you make me do Javascript -slice = Array::slice - -# DOM simplifier (no jQuery dependency) -# NodeJS compatible -$ = (sel, root = document) -> - return sel if typeof sel is "object" or exports? - root.querySelector sel - -class Util - # Unique value utility - @uniqid = do -> - id = 0 - get: -> id++ - - # Helper function that extends one object with all the properies of other objects - @extend = (obj) -> - dest = obj - src = slice.call arguments, 1 - - for copy in src - for own prop of copy - dest[prop] = copy[prop] - - return dest - - # In order to stay true to the latest spec, RGB values must be clamped between - # 0 and 255. If we don't do this, weird things happen. - @clampRGB = (val) -> - return 0 if val < 0 - return 255 if val > 255 - val - - @copyAttributes: (from, to, opts={}) -> - for attr in from.attributes - continue if opts.except? and attr.nodeName in opts.except - to.setAttribute(attr.nodeName, attr.nodeValue) - - # Support for browsers that don't know Uint8Array (such as IE9) - @dataArray: (length = 0) -> - return new Uint8Array(length) if Caman.NodeJS or window.Uint8Array? - return new Array(length) - -# NodeJS compatibility -if exports? - Root = exports - Canvas = require 'canvas' - Image = Canvas.Image - - Fiber = require 'fibers' - - fs = require 'fs' -else - Root = window - -# Here it begins. Caman is defined. -# There are many different initialization for Caman, which are described on the -# [Basic Usage](http://camanjs.com/docs) page. -# -# Initialization is tricky because we need to make sure everything we need is actually fully -# loaded in the DOM before proceeding. When initialized on an image, we need to make sure that the -# image is done loading before converting it to a canvas element and writing the pixel data. If we -# do this prematurely, the browser will throw a DOM Error, and chaos will ensue. In the event that -# we initialize Caman on a canvas element while specifying an image URL, we need to create a new -# image element, load the image, then continue with initialization. -# -# The main goal for Caman was simplicity, so all of this is handled transparently to the end-user. -Root.Caman = class Caman - @version: - release: "4.1.1" - date: "4/8/2013" - - # Debug mode enables console logging - @DEBUG: false - - # Are we in a NodeJS environment? - @NodeJS: exports? - - # Should we check the DOM for images with Caman instructions? - @autoload: not Caman.NodeJS - - # Allow reverting the canvas? - # If your JS process is running out of memory, disabling - # this could help drastically. - @allowRevert: true - - # Default cross-origin policy - @crossOrigin: "anonymous" - - @toString: -> - "Version " + Caman.version.release + ", Released " + Caman.version.date; - - # Set the URL of the image proxy script - @remoteProxy: "" - - # Change the GET param used with the proxy script if needed - @proxyParam: "camanProxyUrl" - - @getAttrId: (canvas) -> - return true if Caman.NodeJS - - if typeof canvas is "string" - canvas = $(canvas) - - return null unless canvas? and canvas.getAttribute? - canvas.getAttribute 'data-caman-id' - - constructor: -> - throw "Invalid arguments" if arguments.length is 0 - - if @ instanceof Caman - # We have to do this to avoid polluting the global scope - # because of how Coffeescript binds functions specified - # with => and the fact that Caman can be invoked as both - # a function and as a 'new' object. - @finishInit = @finishInit.bind(@) - @imageLoaded = @imageLoaded.bind(@) - - args = arguments[0] - - unless Caman.NodeJS - id = parseInt Caman.getAttrId(args[0]), 10 - callback = if typeof args[1] is "function" - args[1] - else if typeof args[2] is "function" - args[2] - else - -> - - if !isNaN(id) and Store.has(id) - return Store.execute(id, callback) - - # Every instance gets a unique ID. Makes it much simpler to check if two variables are the - # same instance. - @id = Util.uniqid.get() - - @initializedPixelData = @originalPixelData = null - @cropCoordinates = x: 0, y: 0 - @cropped = false - @resized = false - - @pixelStack = [] # Stores the pixel layers - @layerStack = [] # Stores all of the layers waiting to be rendered - @canvasQueue = [] # Stores all of the canvases to be processed - @currentLayer = null - @scaled = false - - @analyze = new Analyze @ - @renderer = new Renderer @ - - @domIsLoaded => - @parseArguments(args) - @setup() - - return @ - else - return new Caman(arguments) - - domIsLoaded: (cb) -> - if Caman.NodeJS - setTimeout => - cb.call(@) - , 0 - else - if document.readyState is "complete" - Log.debug "DOM initialized" - setTimeout => - cb.call(@) - , 0 - else - listener = => - if document.readyState is "complete" - Log.debug "DOM initialized" - cb.call(@) - - document.addEventListener "readystatechange", listener, false - - # All possible combinations: - # - # **1 argument** - # - Image selector - # - Image object - # - Canvas selector - # - Canvas object - # - # **2 arguments** - # - Image selector + callback - # - Image object + callback - # - Canvas selector + URL - # - Canvas object + URL - # - # **3 arguments** - # - Canvas selector + URL + callback - # - Canvas object + URL + callback - # - # **NodeJS** - # - file path - # - file object - # - file path + callback - # - file object + callback - parseArguments: (args) -> - throw "Invalid arguments given" if args.length is 0 - - # Defaults - @initObj = null - @initType = null - @imageUrl = null - @callback = -> - - # First argument is always our canvas/image - @setInitObject args[0] - return if args.length is 1 - - switch typeof args[1] - when "string" then @imageUrl = args[1] - when "function" then @callback = args[1] - - return if args.length is 2 - - @callback = args[2] - - if args.length is 4 - @options[key] = val for own key, val of args[4] - - setInitObject: (obj) -> - if Caman.NodeJS - @initObj = obj - @initType = 'node' - return - - if typeof obj is "object" - @initObj = obj - else - @initObj = $(obj) - - throw "Could not find image or canvas for initialization." unless @initObj? - - @initType = @initObj.nodeName.toLowerCase() - - setup: -> - switch @initType - when "node" then @initNode() - when "img" then @initImage() - when "canvas" then @initCanvas() - - initNode: -> - Log.debug "Initializing for NodeJS" - - @image = new Image() - @image.onload = => - Log.debug "Image loaded. Width = #{@imageWidth()}, Height = #{@imageHeight()}" - @canvas = new Canvas @imageWidth(), @imageHeight() - @finishInit() - - @image.onerror = (err) -> throw err - @image.src = @initObj - - initImage: -> - @image = @initObj - @canvas = document.createElement 'canvas' - @context = @canvas.getContext '2d' - Util.copyAttributes @image, @canvas, except: ['src'] - - @image.parentNode.replaceChild @canvas, @image - - @imageAdjustments() - @waitForImageLoaded() - - initCanvas: -> - @canvas = @initObj - @context = @canvas.getContext '2d' - - if @imageUrl? - @image = document.createElement 'img' - @image.src = @imageUrl - - @imageAdjustments() - @waitForImageLoaded() - else - @finishInit() - - imageAdjustments: -> - if @needsHiDPISwap() - Log.debug @image.src, "->", @hiDPIReplacement() - - @swapped = true - @image.src = @hiDPIReplacement() - - if IO.isRemote(@image) - @image.src = IO.proxyUrl(@image.src) - Log.debug "Remote image detected, using URL = #{@image.src}" - - waitForImageLoaded: -> - if @isImageLoaded() - @imageLoaded() - else - @image.onload = @imageLoaded - - isImageLoaded: -> - return false unless @image.complete - return false if @image.naturalWidth? and @image.naturalWidth is 0 - return true - - # Internet Explorer has issues figuring out image dimensions when they aren't - # explicitly defined apparently. We check the normal width/height properties first, - # but fall back to natural sizes if they are 0. - imageWidth: -> @image.width or @image.naturalWidth - imageHeight: -> @image.height or @image.naturalHeight - - imageLoaded: -> - Log.debug "Image loaded. Width = #{@imageWidth()}, Height = #{@imageHeight()}" - - if @swapped - @canvas.width = @imageWidth() / @hiDPIRatio() - @canvas.height = @imageHeight() / @hiDPIRatio() - else - @canvas.width = @imageWidth() - @canvas.height = @imageHeight() - - @finishInit() - - finishInit: -> - @context = @canvas.getContext '2d' unless @context? - - @originalWidth = @preScaledWidth = @width = @canvas.width - @originalHeight = @preScaledHeight = @height = @canvas.height - - @hiDPIAdjustments() - @assignId() unless @hasId() - - if @image? - @context.drawImage @image, - 0, 0, - @imageWidth(), @imageHeight(), - 0, 0, - @preScaledWidth, @preScaledHeight - - @reloadCanvasData() - - if Caman.allowRevert - @initializedPixelData = Util.dataArray(@pixelData.length) - @originalPixelData = Util.dataArray(@pixelData.length) - - for pixel, i in @pixelData - @initializedPixelData[i] = pixel - @originalPixelData[i] = pixel - - @dimensions = - width: @canvas.width - height: @canvas.height - - Store.put @id, @ - - @callback.call @,@ - - # Reset the callback so re-initialization doesn't - # trigger it again. - @callback = -> - - # If you have a separate context reference to this canvas outside of CamanJS - # and you make a change to the canvas outside of CamanJS, you will have to call - # this function to update our context reference to include those changes. - reloadCanvasData: -> - @imageData = @context.getImageData 0, 0, @canvas.width, @canvas.height - @pixelData = @imageData.data - - resetOriginalPixelData: -> - throw "Revert disabled" unless Caman.allowRevert - - @originalPixelData = Util.dataArray(@pixelData.length) - @originalPixelData.push pixel for pixel in @pixelData - - hasId: -> Caman.getAttrId(@canvas)? - - assignId: -> - return if Caman.NodeJS or @canvas.getAttribute 'data-caman-id' - @canvas.setAttribute 'data-caman-id', @id - - hiDPIDisabled: -> - @canvas.getAttribute('data-caman-hidpi-disabled') isnt null - - hiDPIAdjustments: -> - return if Caman.NodeJS or @hiDPIDisabled() - - ratio = @hiDPIRatio() - - if ratio isnt 1 - Log.debug "HiDPI ratio = #{ratio}" - @scaled = true - - @preScaledWidth = @canvas.width - @preScaledHeight = @canvas.height - - @canvas.width = @preScaledWidth * ratio - @canvas.height = @preScaledHeight * ratio - @canvas.style.width = "#{@preScaledWidth}px" - @canvas.style.height = "#{@preScaledHeight}px" - - @context.scale ratio, ratio - - @width = @originalWidth = @canvas.width - @height = @originalHeight = @canvas.height - - hiDPIRatio: -> - devicePixelRatio = window.devicePixelRatio or 1 - backingStoreRatio = @context.webkitBackingStorePixelRatio or - @context.mozBackingStorePixelRatio or - @context.msBackingStorePixelRatio or - @context.oBackingStorePixelRatio or - @context.backingStorePixelRatio or 1 - - devicePixelRatio / backingStoreRatio - - hiDPICapable: -> window.devicePixelRatio? and window.devicePixelRatio isnt 1 - - needsHiDPISwap: -> - return false if @hiDPIDisabled() or !@hiDPICapable() - @hiDPIReplacement() isnt null - - hiDPIReplacement: -> - return null unless @image? - @image.getAttribute 'data-caman-hidpi' - - replaceCanvas: (newCanvas) -> - oldCanvas = @canvas - @canvas = newCanvas - @context = @canvas.getContext '2d' - - oldCanvas.parentNode.replaceChild @canvas, oldCanvas - - @width = @canvas.width - @height = @canvas.height - - @reloadCanvasData() - - @dimensions = - width: @canvas.width - height: @canvas.height - - # Begins the rendering process - render: (callback = ->) -> - Event.trigger @, "renderStart" - - @renderer.execute => - @context.putImageData @imageData, 0, 0 - callback.call @ - - # Reverts the canvas back to it's original state while - # maintaining any cropped or resized dimensions. - revert: -> - throw "Revert disabled" unless Caman.allowRevert - - @pixelData[i] = pixel for pixel, i in @originalVisiblePixels() - @context.putImageData @imageData, 0, 0 - - # Completely resets the canvas back to it's original state. - # Any size adjustments will also be reset. - reset: -> - canvas = document.createElement('canvas') - Util.copyAttributes(@canvas, canvas) - - canvas.width = @originalWidth - canvas.height = @originalHeight - - ctx = canvas.getContext('2d') - imageData = ctx.getImageData 0, 0, canvas.width, canvas.height - pixelData = imageData.data - - pixelData[i] = pixel for pixel, i in @initializedPixelData - - ctx.putImageData imageData, 0, 0 - - @cropCoordinates = x: 0, y: 0 - @resized = false - - @replaceCanvas(canvas) - - # Returns the original pixel data while maintaining any - # cropping or resizing that may have occured. - originalVisiblePixels: -> - throw "Revert disabled" unless Caman.allowRevert - - pixels = [] - - startX = @cropCoordinates.x - endX = startX + @width - startY = @cropCoordinates.y - endY = startY + @height - - if @resized - canvas = document.createElement('canvas') - canvas.width = @originalWidth - canvas.height = @originalHeight - - ctx = canvas.getContext('2d') - imageData = ctx.getImageData 0, 0, canvas.width, canvas.height - pixelData = imageData.data - - pixelData[i] = pixel for pixel, i in @originalPixelData - - ctx.putImageData imageData, 0, 0 - - scaledCanvas = document.createElement('canvas') - scaledCanvas.width = @width - scaledCanvas.height = @height - - ctx = scaledCanvas.getContext('2d') - ctx.drawImage canvas, 0, 0, @originalWidth, @originalHeight, 0, 0, @width, @height - - pixelData = ctx.getImageData(0, 0, @width, @height).data - width = @width - else - pixelData = @originalPixelData - width = @originalWidth - - for i in [0...pixelData.length] by 4 - coord = PixelInfo.locationToCoordinates(i, width) - if (startX <= coord.x < endX) and (startY <= coord.y < endY) - pixels.push pixelData[i], - pixelData[i+1], - pixelData[i+2], - pixelData[i+3] - - pixels - - # Pushes the filter callback that modifies the RGBA object into the - # render queue - process: (name, processFn) -> - @renderer.add - type: Filter.Type.Single - name: name - processFn: processFn - - return @ - - # Pushes the kernel into the render queue - processKernel: (name, adjust, divisor, bias) -> - if not divisor - divisor = 0 - divisor += adjust[i] for i in [0...adjust.length] - - @renderer.add - type: Filter.Type.Kernel - name: name - adjust: adjust - divisor: divisor - bias: bias or 0 - - return @ - - # Adds a standalone plugin into the render queue - processPlugin: (plugin, args) -> - @renderer.add - type: Filter.Type.Plugin - plugin: plugin - args: args - - return @ - - # Pushes a new layer operation into the render queue and calls the layer - # callback - newLayer: (callback) -> - layer = new Layer @ - @canvasQueue.push layer - @renderer.add type: Filter.Type.LayerDequeue - - callback.call layer - - @renderer.add type: Filter.Type.LayerFinished - return @ - - # Pushes the layer context and moves to the next operation - executeLayer: (layer) -> @pushContext layer - - # Set all of the relevant data to the new layer - pushContext: (layer) -> - @layerStack.push @currentLayer - @pixelStack.push @pixelData - @currentLayer = layer - @pixelData = layer.pixelData - - # Restore the previous layer context - popContext: -> - @pixelData = @pixelStack.pop() - @currentLayer = @layerStack.pop() - - # Applies the current layer to its parent layer - applyCurrentLayer: -> @currentLayer.applyToParent() - - -class Analyze - constructor: (@c) -> - - calculateLevels: -> - levels = - r: {} - g: {} - b: {} - - # Initialize all values to 0 first so there are no data gaps - for i in [0..255] - levels.r[i] = 0 - levels.g[i] = 0 - levels.b[i] = 0 - - # Iterate through each pixel block and increment the level counters - for i in [0...@c.pixelData.length] by 4 - levels.r[@c.pixelData[i]]++ - levels.g[@c.pixelData[i+1]]++ - levels.b[@c.pixelData[i+2]]++ - - # Normalize all of the numbers by converting them to percentages between - # 0 and 1.0 - numPixels = @c.pixelData.length / 4 - - for i in [0..255] - levels.r[i] /= numPixels - levels.g[i] /= numPixels - levels.b[i] /= numPixels - - levels - -Caman.DOMUpdated = -> - imgs = document.querySelectorAll("img[data-caman]") - return unless imgs.length > 0 - - for img in imgs - parser = new CamanParser img, -> - @parse() - @execute() - -# If enabled, we check the page to see if there are any -# images with Caman instructions provided using HTML5 -# data attributes. -if Caman.autoload then do -> - if document.readyState is "complete" - Caman.DOMUpdated() - else - document.addEventListener "DOMContentLoaded", Caman.DOMUpdated, false - -# Parses Caman instructions embedded in the HTML data-caman attribute -class CamanParser - INST_REGEX = "(\\w+)\\((.*?)\\)" - - constructor: (ele, ready) -> - @dataStr = ele.getAttribute('data-caman') - @caman = Caman ele, ready.bind(@) - - parse: -> - @ele = @caman.canvas - - # First we find each instruction as a whole using a global - # regex search. - r = new RegExp(INST_REGEX, 'g') - unparsedInstructions = @dataStr.match r - return unless unparsedInstructions.length > 0 - - # Once we gather all the instructions, we go through each one - # and parse out the filter name + it's parameters. - r = new RegExp(INST_REGEX) - for inst in unparsedInstructions - [m, filter, args] = inst.match(r) - - # Create a factory function so we can catch any errors that - # are produced when running the filters. This also makes it very - # simple to support multiple/complex filter arguments. - instFunc = new Function("return function() { - this.#{filter}(#{args}); - };") - - try - func = instFunc() - func.call @caman - catch e - Log.debug e - - execute: -> - ele = @ele - @caman.render -> - ele.parentNode.replaceChild @toImage(), ele - -# Built-in layer blenders. Many of these mimic Photoshop blend modes. -Caman.Blender = class Blender - @blenders = {} - - # Registers a blender. Can be used to add your own blenders outside of - # the core library, if needed. - @register: (name, func) -> @blenders[name] = func - - # Executes a blender to combine a layer with its parent. - @execute: (name, rgbaLayer, rgbaParent) -> - @blenders[name](rgbaLayer, rgbaParent) - -# Various math-heavy helpers -Caman.Calculate = class Calculate - # Calculates the distance between two points - @distance: (x1, y1, x2, y2) -> - Math.sqrt Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) - - # Generates a pseudorandom number that lies within the max - mix range. The number can be either - # an integer or a float depending on what the user specifies. - @randomRange: (min, max, getFloat = false) -> - rand = min + (Math.random() * (max - min)) - return if getFloat then rand.toFixed(getFloat) else Math.round(rand) - - # Calculates the luminance of a single pixel using a special weighted sum - @luminance: (rgba) -> (0.299 * rgba.r) + (0.587 * rgba.g) + (0.114 * rgba.b) - - # Generates a bezier curve given a start and end point, with two control points in between. - # Can also optionally bound the y values between a low and high bound. - # - # This is different than most bezier curve functions because it attempts to construct it in such - # a way that we can use it more like a simple input -> output system, or a one-to-one function. - # In other words we can provide an input color value, and immediately receive an output modified - # color value. - # - # Note that, by design, this does not force X values to be in the range [0..255]. This is to - # generalize the function a bit more. If you give it a starting X value that isn't 0, and/or a - # ending X value that isn't 255, you may run into problems with your filter! - @bezier: (start, ctrl1, ctrl2, end, lowBound, highBound) -> - x0 = start[0] - y0 = start[1] - x1 = ctrl1[0] - y1 = ctrl1[1] - x2 = ctrl2[0] - y2 = ctrl2[1] - x3 = end[0] - y3 = end[1] - bezier = {} - - # Calculate our X/Y coefficients - Cx = parseInt(3 * (x1 - x0), 10) - Bx = 3 * (x2 - x1) - Cx - Ax = x3 - x0 - Cx - Bx - - Cy = 3 * (y1 - y0) - By = 3 * (y2 - y1) - Cy - Ay = y3 - y0 - Cy - By - - # 1000 is actually arbitrary. We need to make sure we do enough - # calculations between 0 and 255 that, in even the more extreme - # circumstances, we calculate as many values as possible. In the event - # that an X value is skipped, it will be found later on using linear - # interpolation. - for i in [0...1000] - t = i / 1000 - - curveX = Math.round (Ax * Math.pow(t, 3)) + (Bx * Math.pow(t, 2)) + (Cx * t) + x0 - curveY = Math.round (Ay * Math.pow(t, 3)) + (By * Math.pow(t, 2)) + (Cy * t) + y0 - - if lowBound and curveY < lowBound - curveY = lowBound - else if highBound and curveY > highBound - curveY = highBound - - bezier[curveX] = curveY - - # Do a search for missing values in the bezier array and use linear - # interpolation to approximate their values - if bezier.length < end[0] + 1 - for i in [0..end[0]] - if not bezier[i]? - leftCoord = [i-1, bezier[i-1]] - - # Find the first value to the right. Ideally this loop will break - # very quickly. - for j in [i..end[0]] - if bezier[j]? - rightCoord = [j, bezier[j]] - break - - bezier[i] = leftCoord[1] + - ((rightCoord[1] - leftCoord[1]) / (rightCoord[0] - leftCoord[0])) * - (i - leftCoord[0]) - - # Edge case - bezier[end[0]] = bezier[end[0] - 1] if not bezier[end[0]]? - - return bezier - - -# Tons of color conversion functions -class Convert - # Converts the hex representation of a color to RGB values. - # Hex value can optionally start with the hash (#). - # - #
-  # @param   String  hex   The colors hex value
-  # @return  Array         The RGB representation
-  # 
- @hexToRGB: (hex) -> - hex = hex.substr(1) if hex.charAt(0) is "#" - r = parseInt hex.substr(0, 2), 16 - g = parseInt hex.substr(2, 2), 16 - b = parseInt hex.substr(4, 2), 16 - - r: r, g: g, b: b - - # Converts an RGB color to HSL. - # Assumes r, g, and b are in the set [0, 255] and - # returns h, s, and l in the set [0, 1]. - # - #
-  # @param   Number  r   Red channel
-  # @param   Number  g   Green channel
-  # @param   Number  b   Blue channel
-  # @return              The HSL representation
-  # 
- @rgbToHSL: (r, g, b) -> - if typeof r is "object" - g = r.g - b = r.b - r = r.r - - r /= 255 - g /= 255 - b /= 255 - - max = Math.max r, g, b - min = Math.min r, g, b - l = (max + min) / 2 - - if max is min - h = s = 0 - else - d = max - min - s = if l > 0.5 then d / (2 - max - min) else d / (max + min) - h = switch max - when r then (g - b) / d + (if g < b then 6 else 0) - when g then (b - r) / d + 2 - when b then (r - g) / d + 4 - - h /= 6 - - h: h, s: s, l: l - - # Converts an HSL color value to RGB. Conversion formula - # adapted from http://en.wikipedia.org/wiki/HSL_color_space. - # Assumes h, s, and l are contained in the set [0, 1] and - # returns r, g, and b in the set [0, 255]. - # - #
-  # @param   Number  h       The hue
-  # @param   Number  s       The saturation
-  # @param   Number  l       The lightness
-  # @return  Array           The RGB representation
-  # 
- @hslToRGB: (h, s, l) -> - if typeof h is "object" - s = h.s - l = h.l - h = h.h - - if s is 0 - r = g = b = l - else - q = if l < 0.5 then l * (1 + s) else l + s - l * s - p = 2 * l - q - - r = @hueToRGB p, q, h + 1/3 - g = @hueToRGB p, q, h - b = @hueToRGB p, q, h - 1/3 - - r: r * 255, g: g * 255, b: b * 255 - - # Converts from the hue color space back to RGB - @hueToRGB: (p, q, t) -> - if t < 0 then t += 1 - if t > 1 then t -= 1 - if t < 1/6 then return p + (q - p) * 6 * t - if t < 1/2 then return q - if t < 2/3 then return p + (q - p) * (2/3 - t) * 6 - return p - - # Converts an RGB color value to HSV. Conversion formula - # adapted from http://en.wikipedia.org/wiki/HSV_color_space. - # Assumes r, g, and b are contained in the set [0, 255] and - # returns h, s, and v in the set [0, 1]. - # - #
-  # @param   Number  r       The red color value
-  # @param   Number  g       The green color value
-  # @param   Number  b       The blue color value
-  # @return  Array           The HSV representation
-  # 
- @rgbToHSV: (r, g, b) -> - r /= 255 - g /= 255 - b /= 255 - - max = Math.max r, g, b - min = Math.min r, g, b - v = max - d = max - min - - s = if max is 0 then 0 else d / max - - if max is min - h = 0 - else - h = switch max - when r then (g - b) / d + (if g < b then 6 else 0) - when g then (b - r) / d + 2 - when b then (r - g) / d + 4 - - h /= 6 - - h: h, s: s, v: v - - # Converts an HSV color value to RGB. Conversion formula - # adapted from http://en.wikipedia.org/wiki/HSV_color_space. - # Assumes h, s, and v are contained in the set [0, 1] and - # returns r, g, and b in the set [0, 255]. - # - #
-  # @param   Number  h       The hue
-  # @param   Number  s       The saturation
-  # @param   Number  v       The value
-  # @return  Array           The RGB representation
-  # 
- @hsvToRGB: (h, s, v) -> - i = Math.floor h * 6 - f = h * 6 - i - p = v * (1 - s) - q = v * (1 - f * s) - t = v * (1 - (1 - f) * s) - - switch i % 6 - when 0 - r = v - g = t - b = p - when 1 - r = q - g = v - b = p - when 2 - r = p - g = v - b = t - when 3 - r = p - g = q - b = v - when 4 - r = t - g = p - b = v - when 5 - r = v - g = p - b = q - - r: r * 255, g: g * 255, b: b * 255 - - # Converts a RGB color value to the XYZ color space. Formulas - # are based on http://en.wikipedia.org/wiki/SRGB assuming that - # RGB values are sRGB. - # - # Assumes r, g, and b are contained in the set [0, 255] and - # returns x, y, and z. - # - #
-  # @param   Number  r       The red color value
-  # @param   Number  g       The green color value
-  # @param   Number  b       The blue color value
-  # @return  Array           The XYZ representation
-  # 
- @rgbToXYZ: (r, g, b) -> - r /= 255 - g /= 255 - b /= 255 - - if r > 0.04045 - r = Math.pow((r + 0.055) / 1.055, 2.4) - else - r /= 12.92 - - if g > 0.04045 - g = Math.pow((g + 0.055) / 1.055, 2.4) - else - g /= 12.92 - - if b > 0.04045 - b = Math.pow((b + 0.055) / 1.055, 2.4) - else - b /= 12.92 - - x = r * 0.4124 + g * 0.3576 + b * 0.1805; - y = r * 0.2126 + g * 0.7152 + b * 0.0722; - z = r * 0.0193 + g * 0.1192 + b * 0.9505; - - x: x * 100, y: y * 100, z: z * 100 - - # Converts a XYZ color value to the sRGB color space. Formulas - # are based on http://en.wikipedia.org/wiki/SRGB and the resulting - # RGB value will be in the sRGB color space. - # Assumes x, y and z values are whatever they are and returns - # r, g and b in the set [0, 255]. - # - #
-  # @param   Number  x       The X value
-  # @param   Number  y       The Y value
-  # @param   Number  z       The Z value
-  # @return  Array           The RGB representation
-  # 
- @xyzToRGB: (x, y, z) -> - x /= 100 - y /= 100 - z /= 100 - - r = (3.2406 * x) + (-1.5372 * y) + (-0.4986 * z) - g = (-0.9689 * x) + (1.8758 * y) + (0.0415 * z) - b = (0.0557 * x) + (-0.2040 * y) + (1.0570 * z) - - if r > 0.0031308 - r = (1.055 * Math.pow(r, 0.4166666667)) - 0.055 - else - r *= 12.92 - - if g > 0.0031308 - g = (1.055 * Math.pow(g, 0.4166666667)) - 0.055 - else - g *= 12.92 - - if b > 0.0031308 - b = (1.055 * Math.pow(b, 0.4166666667)) - 0.055 - else - b *= 12.92 - - r: r * 255, g: g * 255, b: b * 255 - - # Converts a XYZ color value to the CIELAB color space. Formulas - # are based on http://en.wikipedia.org/wiki/Lab_color_space - # The reference white point used in the conversion is D65. - # Assumes x, y and z values are whatever they are and returns - # L*, a* and b* values - # - #
-  # @param   Number  x       The X value
-  # @param   Number  y       The Y value
-  # @param   Number  z       The Z value
-  # @return  Array           The Lab representation
-  # 
- @xyzToLab: (x, y, z) -> - if typeof x is "object" - y = x.y - z = x.z - x = x.x - - whiteX = 95.047 - whiteY = 100.0 - whiteZ = 108.883 - - x /= whiteX - y /= whiteY - z /= whiteZ - - if x > 0.008856451679 - x = Math.pow(x, 0.3333333333) - else - x = (7.787037037 * x) + 0.1379310345 - - if y > 0.008856451679 - y = Math.pow(y, 0.3333333333) - else - y = (7.787037037 * y) + 0.1379310345 - - if z > 0.008856451679 - z = Math.pow(z, 0.3333333333) - else - z = (7.787037037 * z) + 0.1379310345 - - l = 116 * y - 16 - a = 500 * (x - y) - b = 200 * (y - z) - - l: l, a: a, b: b - - # Converts a L*, a*, b* color values from the CIELAB color space - # to the XYZ color space. Formulas are based on - # http://en.wikipedia.org/wiki/Lab_color_space - # - # The reference white point used in the conversion is D65. - # Assumes L*, a* and b* values are whatever they are and returns - # x, y and z values. - # - #
-  # @param   Number  l       The L* value
-  # @param   Number  a       The a* value
-  # @param   Number  b       The b* value
-  # @return  Array           The XYZ representation
-  # 
- @labToXYZ: (l, a, b) -> - if typeof l is "object" - a = l.a - b = l.b - l = l.l - - y = (l + 16) / 116 - x = y + (a / 500) - z = y - (b / 200) - - if x > 0.2068965517 - x = x * x * x - else - x = 0.1284185493 * (x - 0.1379310345) - - if y > 0.2068965517 - y = y * y * y - else - y = 0.1284185493 * (y - 0.1379310345) - - if z > 0.2068965517 - z = z * z * z - else - z = 0.1284185493 * (z - 0.1379310345) - - # D65 reference white point - x: x * 95.047, y: y * 100.0, z: z * 108.883 - - @rgbToLab: (r, g, b) -> - if typeof r is "object" - g = r.g - b = r.b - r = r.r - - xyz = @rgbToXYZ(r, g, b) - @xyzToLab xyz - - @labToRGB: (l, a, b) -> - - -# Event system that can be used to register callbacks that get fired -# during certain times in the render process. -class Event - @events = {} - - # All of the supported event types - @types = [ - "processStart" - "processComplete" - "renderStart" - "renderFinished" - "blockStarted" - "blockFinished" - ] - - # Trigger an event - @trigger: (target, type, data) -> - if @events[type] and @events[type].length - for event in @events[type] - if event.target is null or target.id is event.target.id - event.fn.call target, data - - # Listen for an event. Optionally bind the listen to a single CamanInstance - # or all CamanInstances. - @listen: (target, type, fn) -> - # Adjust arguments if target is omitted - if typeof target is "string" - _type = target - _fn = type - - target = null - type = _type - fn = _fn - - # Validation - return false if type not in @types - - @events[type] = [] if not @events[type] - @events[type].push target: target, fn: fn - - return true - -Caman.Event = Event - -# Responsible for storing all of the filters -Caman.Filter = class Filter - # All of the different render operatives - @Type = - Single: 1 - Kernel: 2 - LayerDequeue: 3 - LayerFinished: 4 - LoadOverlay: 5 - Plugin: 6 - - # Registers a filter function - @register: (name, filterFunc) -> Caman::[name] = filterFunc - -# Various I/O based operations -Caman.IO = class IO - @domainRegex = /(?:(?:http|https):\/\/)((?:\w+)\.(?:(?:\w|\.)+))/ - - # Is the given URL remote? - # If a cross-origin setting is set, we assume you have CORS - # properly configured. - @isRemote: (img) -> - return false unless img? - return false if @corsEnabled(img) - return @isURLRemote img.src - - @corsEnabled: (img) -> - img.crossOrigin? and img.crossOrigin.toLowerCase() in ['anonymous', 'use-credentials'] - - @isURLRemote: (url) -> - matches = url.match @domainRegex - return if matches then matches[1] isnt document.domain else false - - @remoteCheck: (src) -> - if @isURLRemote src - if not Caman.remoteProxy.length - Log.info "Attempting to load a remote image without a configured proxy. URL: #{src}" - return - else - if Caman.isURLRemote Caman.remoteProxy - Log.info "Cannot use a remote proxy for loading images." - return - - "#{Caman.remoteProxy}?camanProxyUrl=#{encodeURIComponent(src)}" - - - @proxyUrl: (src) -> - "#{Caman.remoteProxy}?#{Caman.proxyParam}=#{encodeURIComponent(src)}" - - # Shortcut for using one of the bundled proxies. - @useProxy: (lang) -> - langToExt = - ruby: 'rb' - python: 'py' - perl: 'pl' - javascript: 'js' - - lang = lang.toLowerCase() - lang = langToExt[lang] if langToExt[lang]? - "proxies/caman_proxy.#{lang}" - -# Grabs the canvas data, encodes it to Base64, then sets the browser location to -# the encoded data so that the user will be prompted to download it. -Caman::save = -> - if exports? - @nodeSave.apply @, arguments - else - @browserSave.apply @, arguments - -Caman::browserSave = (type = "png") -> - type = type.toLowerCase() - - # Force download (its a bit hackish) - image = @toBase64(type).replace "image/#{type}", "image/octet-stream" - document.location.href = image - -Caman::nodeSave = (file, overwrite = true) -> - try - stats = fs.statSync file - return false if stats.isFile() and not overwrite - catch e - Log.debug "Creating output file #{file}" - - fs.writeFile file, @canvas.toBuffer(), -> - Log.debug "Finished writing to #{file}" - -# Takes the current canvas data, converts it to Base64, then sets it as the source -# of a new Image object and returns it. -Caman::toImage = (type) -> - img = document.createElement 'img' - img.src = @toBase64 type - img.width = @dimensions.width - img.height = @dimensions.height - - if window.devicePixelRatio - img.width /= window.devicePixelRatio - img.height /= window.devicePixelRatio - - return img - -# Base64 encodes the current canvas -Caman::toBase64 = (type = "png") -> - type = type.toLowerCase() - return @canvas.toDataURL "image/#{type}" - - -# The entire layering system for Caman resides in this file. Layers get their own canvasLayer -# objectwhich is created when newLayer() is called. For extensive information regarding the -# specifics of howthe layering system works, there is an in-depth blog post on this very topic. -# Instead of copying the entirety of that post, I'll simply point you towards the -# [blog link](http://blog.meltingice.net/programming/implementing-layers-camanjs). -# -# However, the gist of the layering system is that, for each layer, it creates a new canvas -# element and then either copies the parent layer's data or applies a solid color to the new -# layer. After some (optional) effects are applied, the layer is blended back into the parent -# canvas layer using one of many different blending algorithms. -# -# You can also load an image (local or remote, with a proxy) into a canvas layer, which is useful -# if you want to add textures to an image. -class Layer - constructor: (@c) -> - # Compatibility - @filter = @c - - @options = - blendingMode: 'normal' - opacity: 1.0 - - # Each layer gets its own unique ID - @layerID = Util.uniqid.get() - - # Create the canvas for this layer - @canvas = if exports? then new Canvas() else document.createElement('canvas') - - @canvas.width = @c.dimensions.width - @canvas.height = @c.dimensions.height - - @context = @canvas.getContext('2d') - @context.createImageData @canvas.width, @canvas.height - @imageData = @context.getImageData 0, 0, @canvas.width, @canvas.height - @pixelData = @imageData.data - - # If you want to create nested layers - newLayer: (cb) -> @c.newLayer.call @c, cb - - # Sets the blending mode of this layer. The mode is the name of a blender function. - setBlendingMode: (mode) -> - @options.blendingMode = mode - return @ - - # Sets the opacity of this layer. This affects how much of this layer is applied to the parent - # layer at render time. - opacity: (opacity) -> - @options.opacity = opacity / 100 - return @ - - # Copies the contents of the parent layer to this layer - copyParent: -> - parentData = @c.pixelData - - for i in [0...@c.pixelData.length] by 4 - @pixelData[i] = parentData[i] - @pixelData[i+1] = parentData[i+1] - @pixelData[i+2] = parentData[i+2] - @pixelData[i+3] = parentData[i+3] - - return @ - - # Fills this layer with a single color - fillColor: -> @c.fillColor.apply @c, arguments - - # Loads and overlays an image onto this layer - overlayImage: (image) -> - if typeof image is "object" - image = image.src - else if typeof image is "string" and image[0] is "#" - image = $(image).src - - return @ if not image - - @c.renderer.renderQueue.push - type: Filter.Type.LoadOverlay - src: image - layer: @ - - return @ - - # Takes the contents of this layer and applies them to the parent layer at render time. This - # should never be called explicitly by the user. - applyToParent: -> - parentData = @c.pixelStack[@c.pixelStack.length - 1] - layerData = @c.pixelData - - for i in [0...layerData.length] by 4 - rgbaParent = - r: parentData[i] - g: parentData[i+1] - b: parentData[i+2] - a: parentData[i+3] - - rgbaLayer = - r: layerData[i] - g: layerData[i+1] - b: layerData[i+2] - a: layerData[i+3] - - result = Blender.execute @options.blendingMode, rgbaLayer, rgbaParent - - result.r = Util.clampRGB result.r - result.g = Util.clampRGB result.g - result.b = Util.clampRGB result.b - result.a = rgbaLayer.a if not result.a? - - parentData[i] = rgbaParent.r - ( - (rgbaParent.r - result.r) * (@options.opacity * (result.a / 255)) - ) - parentData[i+1] = rgbaParent.g - ( - (rgbaParent.g - result.g) * (@options.opacity * (result.a / 255)) - ) - parentData[i+2] = rgbaParent.b - ( - (rgbaParent.b - result.b) * (@options.opacity * (result.a / 255)) - ) - - -# Simple console logger class that can be toggled on and off based on Caman.DEBUG -class Logger - constructor: -> - for name in ['log', 'info', 'warn', 'error'] - @[name] = do (name) -> - (args...) -> - return if not Caman.DEBUG - try - console[name].apply console, args - catch e - # We're probably using IE9 or earlier - console[name] args - - @debug = @log - -Log = new Logger() - -# This object is available inside of the process() loop, and it lets filter developers have simple -# access to any arbitrary pixel in the image, as well as information about the current pixel in -# the loop. -class PixelInfo - @coordinatesToLocation: (x, y, width) -> - (y * width + x) * 4 - - @locationToCoordinates: (loc, width) -> - y = Math.floor(loc / (width * 4)) - x = (loc % (width * 4)) / 4 - - return x: x, y: y - - constructor: (@c) -> @loc = 0 - - # Retrieves the X, Y location of the current pixel. The origin is at the bottom left corner of - # the image, like a normal coordinate system. - locationXY: -> - y = @c.dimensions.height - Math.floor(@loc / (@c.dimensions.width * 4)) - x = (@loc % (@c.dimensions.width * 4)) / 4 - - return x: x, y: y - - # Returns an RGBA object for a pixel whose location is specified in relation to the current - # pixel. - getPixelRelative: (horiz, vert) -> - # We invert the vert_offset in order to make the coordinate system non-inverted. In laymans - # terms: -1 means down and +1 means up. - newLoc = @loc + (@c.dimensions.width * 4 * (vert * -1)) + (4 * horiz) - - if newLoc > @c.pixelData.length or newLoc < 0 - return r: 0, g: 0, b: 0, a: 0 - - return { - r: @c.pixelData[newLoc] - g: @c.pixelData[newLoc + 1] - b: @c.pixelData[newLoc + 2] - a: @c.pixelData[newLoc + 3] - } - - # The counterpart to getPixelRelative, this updates the value of a pixel whose location is - # specified in relation to the current pixel. - putPixelRelative: (horiz, vert, rgba) -> - nowLoc = @loc + (@c.dimensions.width * 4 * (vert * -1)) + (4 * horiz) - - return if newLoc > @c.pixelData.length or newLoc < 0 - - @c.pixelData[newLoc] = rgba.r - @c.pixelData[newLoc + 1] = rgba.g - @c.pixelData[newLoc + 2] = rgba.b - @c.pixelData[newLoc + 3] = rgba.a - - return true - - # Gets an RGBA object for an arbitrary pixel in the canvas specified by absolute X, Y coordinates - getPixel: (x, y) -> - loc = @coordinatesToLocation(x, y, @width) - - return { - r: @c.pixelData[loc] - g: @c.pixelData[loc + 1] - b: @c.pixelData[loc + 2] - a: @c.pixelData[loc + 3] - } - - # Updates the pixel at the given X, Y coordinate - putPixel: (x, y, rgba) -> - loc = @coordinatesToLocation(x, y, @width) - - @c.pixelData[loc] = rgba.r - @c.pixelData[loc + 1] = rgba.g - @c.pixelData[loc + 2] = rgba.b - @c.pixelData[loc + 3] = rgba.a - - -# Stores and registers standalone plugins -class Plugin - @plugins = {} - - @register: (name, plugin) -> @plugins[name] = plugin - @execute: (context, name, args) -> @plugins[name].apply context, args - -Caman.Plugin = Plugin - -# Handles all of the various rendering methods in Caman. Most of the image modification happens -# here. A new Renderer object is created for every render operation. -Caman.Renderer = class Renderer - # The number of blocks to split the image into during the render process to simulate - # concurrency. This also helps the browser manage the (possibly) long running render jobs. - @Blocks = if Caman.NodeJS then require('os').cpus().length else 4 - - constructor: (@c) -> - @renderQueue = [] - @modPixelData = null - - add: (job) -> - return unless job? - @renderQueue.push job - - # Grabs the next operation from the render queue and passes it to Renderer - # for execution - processNext: => - # If the queue is empty, fire the finished callback - if @renderQueue.length is 0 - Event.trigger @, "renderFinished" - @finishedFn.call(@c) if @finishedFn? - - return @ - - @currentJob = @renderQueue.shift() - - switch @currentJob.type - when Filter.Type.LayerDequeue - layer = @c.canvasQueue.shift() - @c.executeLayer layer - @processNext() - when Filter.Type.LayerFinished - @c.applyCurrentLayer() - @c.popContext() - @processNext() - when Filter.Type.LoadOverlay - @loadOverlay @currentJob.layer, @currentJob.src - when Filter.Type.Plugin - @executePlugin() - else - @executeFilter() - - execute: (callback) -> - @finishedFn = callback - @modPixelData = Util.dataArray(@c.pixelData.length) - - @processNext() - - eachBlock: (fn) -> - # Prepare all the required render data - @blocksDone = 0 - - n = @c.pixelData.length - blockPixelLength = Math.floor (n / 4) / Renderer.Blocks - blockN = blockPixelLength * 4 - lastBlockN = blockN + ((n / 4) % Renderer.Blocks) * 4 - - for i in [0...Renderer.Blocks] - start = i * blockN - end = start + (if i is Renderer.Blocks - 1 then lastBlockN else blockN) - - if Caman.NodeJS - f = Fiber => fn.call(@, i, start, end) - bnum = f.run() - @blockFinished(bnum) - else - setTimeout do (i, start, end) => - => fn.call(@, i, start, end) - , 0 - - # The core of the image rendering, this function executes the provided filter. - # - # NOTE: this does not write the updated pixel data to the canvas. That happens when all filters - # are finished rendering in order to be as fast as possible. - executeFilter: -> - Event.trigger @c, "processStart", @currentJob - - if @currentJob.type is Filter.Type.Single - @eachBlock @renderBlock - else - @eachBlock @renderKernel - - # Executes a standalone plugin - executePlugin: -> - Log.debug "Executing plugin #{@currentJob.plugin}" - Plugin.execute @c, @currentJob.plugin, @currentJob.args - Log.debug "Plugin #{@currentJob.plugin} finished!" - - @processNext() - - # Renders a single block of the canvas with the current filter function - renderBlock: (bnum, start, end) -> - Log.debug "Block ##{bnum} - Filter: #{@currentJob.name}, Start: #{start}, End: #{end}" - Event.trigger @c, "blockStarted", - blockNum: bnum - totalBlocks: Renderer.Blocks - startPixel: start - endPixel: end - - data = r: 0, g: 0, b: 0, a: 0 - pixelInfo = new PixelInfo @c - - for i in [start...end] by 4 - pixelInfo.loc = i - - data.r = @c.pixelData[i] - data.g = @c.pixelData[i+1] - data.b = @c.pixelData[i+2] - data.a = @c.pixelData[i+3] - - res = @currentJob.processFn.call pixelInfo, data - res.a = data.a if not res.a? - - @c.pixelData[i] = Util.clampRGB res.r - @c.pixelData[i+1] = Util.clampRGB res.g - @c.pixelData[i+2] = Util.clampRGB res.b - @c.pixelData[i+3] = Util.clampRGB res.a - - if Caman.NodeJS - Fiber.yield(bnum) - else - @blockFinished bnum - - # Applies an image kernel to the canvas - renderKernel: (bnum, start, end) -> - name = @currentJob.name - bias = @currentJob.bias - divisor = @currentJob.divisor - n = @c.pixelData.length - - adjust = @currentJob.adjust - adjustSize = Math.sqrt adjust.length - - kernel = [] - - Log.debug "Rendering kernel - Filter: #{@currentJob.name}" - - start = Math.max start, @c.dimensions.width * 4 * ((adjustSize - 1) / 2) - end = Math.min end, n - (@c.dimensions.width * 4 * ((adjustSize - 1) / 2)) - - builder = (adjustSize - 1) / 2 - - pixelInfo = new PixelInfo @c - - for i in [start...end] by 4 - pixelInfo.loc = i - builderIndex = 0 - - for j in [-builder..builder] - for k in [builder..-builder] - pixel = pixelInfo.getPixelRelative j, k - kernel[builderIndex * 3] = pixel.r - kernel[builderIndex * 3 + 1] = pixel.g - kernel[builderIndex * 3 + 2] = pixel.b - - builderIndex++ - - res = @processKernel adjust, kernel, divisor, bias - - @modPixelData[i] = Util.clampRGB(res.r) - @modPixelData[i+1] = Util.clampRGB(res.g) - @modPixelData[i+2] = Util.clampRGB(res.b) - @modPixelData[i+3] = @c.pixelData[i+3] - - if Caman.NodeJS - Fiber.yield(bnum) - else - @blockFinished bnum - - # Called when a single block is finished rendering. Once all blocks are done, we signal that this - # filter is finished rendering and continue to the next step. - blockFinished: (bnum) -> - Log.debug "Block ##{bnum} finished! Filter: #{@currentJob.name}" if bnum >= 0 - @blocksDone++ - - Event.trigger @c, "blockFinished", - blockNum: bnum - blocksFinished: @blocksDone - totalBlocks: Renderer.Blocks - - if @blocksDone is Renderer.Blocks - if @currentJob.type is Filter.Type.Kernel - for i in [0...@c.pixelData.length] - @c.pixelData[i] = @modPixelData[i] - - Log.debug "Filter #{@currentJob.name} finished!" if bnum >=0 - Event.trigger @c, "processComplete", @currentJob - - @processNext() - - # The "filter function" for kernel adjustments. - processKernel: (adjust, kernel, divisor, bias) -> - val = r: 0, g: 0, b: 0 - - for i in [0...adjust.length] - val.r += adjust[i] * kernel[i * 3] - val.g += adjust[i] * kernel[i * 3 + 1] - val.b += adjust[i] * kernel[i * 3 + 2] - - val.r = (val.r / divisor) + bias - val.g = (val.g / divisor) + bias - val.b = (val.b / divisor) + bias - val - - # Loads an image onto the current canvas - loadOverlay: (layer, src) -> - img = document.createElement 'img' - img.onload = => - layer.context.drawImage img, 0, 0, @c.dimensions.width, @c.dimensions.height - layer.imageData = layer.context.getImageData 0, 0, @c.dimensions.width, @c.dimensions.height - layer.pixelData = layer.imageData.data - - @c.pixelData = layer.pixelData - - @processNext() - - proxyUrl = IO.remoteCheck src - img.src = if proxyUrl? then proxyUrl else src - -# Used for storing instances of CamanInstance objects such that, when Caman() is called on an -# already initialized element, it returns that object instead of re-initializing. -Caman.Store = class Store - @items = {} - - @has: (search) -> @items[search]? - @get: (search) -> @items[search] - @put: (name, obj) -> @items[name] = obj - @execute: (search, callback) -> - setTimeout => - callback.call @get(search), @get(search) - , 0 - - return @get(search) - - @flush: (name = false) -> - if name then delete @items[name] else @items = {} - -# Directly apply the child layer's pixels to the parent layer with no special changes -Blender.register "normal", (rgbaLayer, rgbaParent) -> - r: rgbaLayer.r - g: rgbaLayer.g - b: rgbaLayer.b - -# Apply the child to the parent by multiplying the color values. This generally creates contrast. -Blender.register "multiply", (rgbaLayer, rgbaParent) -> - r: (rgbaLayer.r * rgbaParent.r) / 255 - g: (rgbaLayer.g * rgbaParent.g) / 255 - b: (rgbaLayer.b * rgbaParent.b) / 255 - -Blender.register "screen", (rgbaLayer, rgbaParent) -> - r: 255 - (((255 - rgbaLayer.r) * (255 - rgbaParent.r)) / 255) - g: 255 - (((255 - rgbaLayer.g) * (255 - rgbaParent.g)) / 255) - b: 255 - (((255 - rgbaLayer.b) * (255 - rgbaParent.b)) / 255) - - -Blender.register "overlay", (rgbaLayer, rgbaParent) -> - result = {} - result.r = - if rgbaParent.r > 128 - 255 - 2 * (255 - rgbaLayer.r) * (255 - rgbaParent.r) / 255 - else (rgbaParent.r * rgbaLayer.r * 2) / 255 - - result.g = - if rgbaParent.g > 128 - 255 - 2 * (255 - rgbaLayer.g) * (255 - rgbaParent.g) / 255 - else (rgbaParent.g * rgbaLayer.g * 2) / 255 - - result.b = - if rgbaParent.b > 128 - 255 - 2 * (255 - rgbaLayer.b) * (255 - rgbaParent.b) / 255 - else (rgbaParent.b * rgbaLayer.b * 2) / 255 - - result - -Blender.register "difference", (rgbaLayer, rgbaParent) -> - r: rgbaLayer.r - rgbaParent.r - g: rgbaLayer.g - rgbaParent.g - b: rgbaLayer.b - rgbaParent.b - -Blender.register "addition", (rgbaLayer, rgbaParent) -> - r: rgbaParent.r + rgbaLayer.r - g: rgbaParent.g + rgbaLayer.g - b: rgbaParent.b + rgbaLayer.b - -Blender.register "exclusion", (rgbaLayer, rgbaParent) -> - r: 128 - 2 * (rgbaParent.r - 128) * (rgbaLayer.r - 128) / 255 - g: 128 - 2 * (rgbaParent.g - 128) * (rgbaLayer.g - 128) / 255 - b: 128 - 2 * (rgbaParent.b - 128) * (rgbaLayer.b - 128) / 255 - -Blender.register "softLight", (rgbaLayer, rgbaParent) -> - result = {} - - result.r = - if rgbaParent.r > 128 - 255 - ((255 - rgbaParent.r) * (255 - (rgbaLayer.r - 128))) / 255 - else (rgbaParent.r * (rgbaLayer.r + 128)) / 255 - - result.g = - if rgbaParent.g > 128 - 255 - ((255 - rgbaParent.g) * (255 - (rgbaLayer.g - 128))) / 255 - else (rgbaParent.g * (rgbaLayer.g + 128)) / 255 - - result.b = - if rgbaParent.b > 128 - 255 - ((255 - rgbaParent.b) * (255 - (rgbaLayer.b - 128))) / 255 - else (rgbaParent.b * (rgbaLayer.b + 128)) / 255 - - result - -Blender.register "lighten", (rgbaLayer, rgbaParent) -> - r: if rgbaParent.r > rgbaLayer.r then rgbaParent.r else rgbaLayer.r - g: if rgbaParent.g > rgbaLayer.g then rgbaParent.g else rgbaLayer.g - b: if rgbaParent.b > rgbaLayer.b then rgbaParent.b else rgbaLayer.b - -Blender.register "darken", (rgbaLayer, rgbaParent) -> - r: if rgbaParent.r > rgbaLayer.r then rgbaLayer.r else rgbaParent.r - g: if rgbaParent.g > rgbaLayer.g then rgbaLayer.g else rgbaParent.g - b: if rgbaParent.b > rgbaLayer.b then rgbaLayer.b else rgbaParent.b - -# The filters define all of the built-in functionality that comes with Caman (as opposed to being -# provided by a plugin). All of these filters are ratherbasic, but are extremely powerful when -# many are combined. For information on creating plugins, check out the -# [Plugin Creation](http://camanjs.com/docs/plugin-creation) page, and for information on using -# the plugins, check out the [Built-In Functionality](http://camanjs.com/docs/built-in) page. - -# ## Fill Color -# Fills the canvas with a single solid color. -# -# ### Arguments -# Can take either separate R, G, and B values as arguments, or a single hex color value. -Filter.register "fillColor", -> - if arguments.length is 1 - color = Convert.hexToRGB arguments[0] - else - color = - r: arguments[0] - g: arguments[1] - b: arguments[2] - - @process "fillColor", (rgba) -> - rgba.r = color.r - rgba.g = color.g - rgba.b = color.b - rgba.a = 255 - rgba - -# ## Brightness -# Simple brightness adjustment -# -# ### Arguments -# Range is -100 to 100. Values < 0 will darken image while values > 0 will brighten. -Filter.register "brightness", (adjust) -> - adjust = Math.floor 255 * (adjust / 100) - - @process "brightness", (rgba) -> - rgba.r += adjust - rgba.g += adjust - rgba.b += adjust - rgba - -# ## Saturation -# Adjusts the color saturation of the image. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will desaturate the image while values > 0 will saturate it. -# **If you want to completely desaturate the image**, using the greyscale filter is highly -# recommended because it will yield better results. -Filter.register "saturation", (adjust) -> - adjust *= -0.01 - - @process "saturation", (rgba) -> - max = Math.max rgba.r, rgba.g, rgba.b - - rgba.r += (max - rgba.r) * adjust if rgba.r isnt max - rgba.g += (max - rgba.g) * adjust if rgba.g isnt max - rgba.b += (max - rgba.b) * adjust if rgba.b isnt max - rgba - -# ## Vibrance -# Similar to saturation, but adjusts the saturation levels in a slightly smarter, more subtle way. -# Vibrance will attempt to boost colors that are less saturated more and boost already saturated -# colors less, while saturation boosts all colors by the same level. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will desaturate the image while values > 0 will saturate it. -# **If you want to completely desaturate the image**, using the greyscale filter is highly -# recommended because it will yield better results. -Filter.register "vibrance", (adjust) -> - adjust *= -1 - - @process "vibrance", (rgba) -> - max = Math.max rgba.r, rgba.g, rgba.b - avg = (rgba.r + rgba.g + rgba.b) / 3 - amt = ((Math.abs(max - avg) * 2 / 255) * adjust) / 100 - - rgba.r += (max - rgba.r) * amt if rgba.r isnt max - rgba.g += (max - rgba.g) * amt if rgba.g isnt max - rgba.b += (max - rgba.b) * amt if rgba.b isnt max - rgba - -# ## Greyscale -# An improved greyscale function that should make prettier results -# than simply using the saturation filter to remove color. It does so by using factors -# that directly relate to how the human eye perceves color and values. There are -# no arguments, it simply makes the image greyscale with no in-between. -# -# Algorithm adopted from http://www.phpied.com/image-fun/ -Filter.register "greyscale", (adjust) -> - @process "greyscale", (rgba) -> - # Calculate the average value of the 3 color channels - # using the special factors - avg = Calculate.luminance(rgba) - - rgba.r = avg - rgba.g = avg - rgba.b = avg - rgba - -# ## Contrast -# Increases or decreases the color contrast of the image. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will decrease contrast while values > 0 will increase contrast. -# The contrast adjustment values are a bit sensitive. While unrestricted, sane adjustment values -# are usually around 5-10. -Filter.register "contrast", (adjust) -> - adjust = Math.pow((adjust + 100) / 100, 2) - - @process "contrast", (rgba) -> - # Red channel - rgba.r /= 255; - rgba.r -= 0.5; - rgba.r *= adjust; - rgba.r += 0.5; - rgba.r *= 255; - - # Green channel - rgba.g /= 255; - rgba.g -= 0.5; - rgba.g *= adjust; - rgba.g += 0.5; - rgba.g *= 255; - - # Blue channel - rgba.b /= 255; - rgba.b -= 0.5; - rgba.b *= adjust; - rgba.b += 0.5; - rgba.b *= 255; - - rgba - -# ## Hue -# Adjusts the hue of the image. It can be used to shift the colors in an image in a uniform -# fashion. If you are unfamiliar with Hue, I recommend reading this -# [Wikipedia article](http://en.wikipedia.org/wiki/Hue). -# -# ### Arguments -# Range is 0 to 100 -# Sometimes, Hue is expressed in the range of 0 to 360. If that's the terminology you're used to, -# think of 0 to 100 representing the percentage of Hue shift in the 0 to 360 range. -Filter.register "hue", (adjust) -> - @process "hue", (rgba) -> - hsv = Convert.rgbToHSV rgba.r, rgba.g, rgba.b - - h = hsv.h * 100 - h += Math.abs adjust - h = h % 100 - h /= 100 - hsv.h = h - - rgb = Convert.hsvToRGB hsv.h, hsv.s, hsv.v - rgb.a = rgba.a - rgb - -# ## Colorize -# Uniformly shifts the colors in an image towards the given color. The adjustment range is from 0 -# to 100. The higher the value, the closer the colors in the image shift towards the given -# adjustment color. -# -# ### Arguments -# This filter is polymorphic and can take two different sets of arguments. Either a hex color -# string and an adjustment value, or RGB colors and an adjustment value. -Filter.register "colorize", -> - if arguments.length is 2 - rgb = Convert.hexToRGB(arguments[0]) - level = arguments[1] - else if arguments.length is 4 - rgb = - r: arguments[0] - g: arguments[1] - b: arguments[2] - - level = arguments[3] - - @process "colorize", (rgba) -> - rgba.r -= (rgba.r - rgb.r) * (level / 100) - rgba.g -= (rgba.g - rgb.g) * (level / 100) - rgba.b -= (rgba.b - rgb.b) * (level / 100) - rgba - -# ## Invert -# Inverts all colors in the image by subtracting each color channel value from 255. No arguments. -Filter.register "invert", -> - @process "invert", (rgba) -> - rgba.r = 255 - rgba.r - rgba.g = 255 - rgba.g - rgba.b = 255 - rgba.b - rgba - -# ## Sepia -# Applies an adjustable sepia filter to the image. -# -# ### Arguments -# Assumes adjustment is between 0 and 100, which represents how much the sepia filter is applied. -Filter.register "sepia", (adjust = 100) -> - adjust /= 100 - - @process "sepia", (rgba) -> - # All three color channels have special conversion factors that - # define what sepia is. Here we adjust each channel individually, - # with the twist that you can partially apply the sepia filter. - rgba.r = Math.min(255, (rgba.r * (1 - (0.607 * adjust))) + (rgba.g * (0.769 * adjust)) + (rgba.b * (0.189 * adjust))); - rgba.g = Math.min(255, (rgba.r * (0.349 * adjust)) + (rgba.g * (1 - (0.314 * adjust))) + (rgba.b * (0.168 * adjust))); - rgba.b = Math.min(255, (rgba.r * (0.272 * adjust)) + (rgba.g * (0.534 * adjust)) + (rgba.b * (1- (0.869 * adjust)))); - - rgba - -# ## Gamma -# Adjusts the gamma of the image. -# -# ### Arguments -# Range is from 0 to infinity, although sane values are from 0 to 4 or 5. -# Values between 0 and 1 will lessen the contrast while values greater than 1 will increase it. -Filter.register "gamma", (adjust) -> - @process "gamma", (rgba) -> - rgba.r = Math.pow(rgba.r / 255, adjust) * 255 - rgba.g = Math.pow(rgba.g / 255, adjust) * 255 - rgba.b = Math.pow(rgba.b / 255, adjust) * 255 - rgba - -# ## Noise -# Adds noise to the image on a scale from 1 - 100. However, the scale isn't constrained, so you -# can specify a value > 100 if you want a LOT of noise. -Filter.register "noise", (adjust) -> - adjust = Math.abs(adjust) * 2.55 - - @process "noise", (rgba) -> - rand = Calculate.randomRange adjust * -1, adjust - - rgba.r += rand - rgba.g += rand - rgba.b += rand - rgba - -# ## Clip -# Clips a color to max values when it falls outside of the specified range. -# -# ### Arguments -# Supplied value should be between 0 and 100. -Filter.register "clip", (adjust) -> - adjust = Math.abs(adjust) * 2.55 - - @process "clip", (rgba) -> - if rgba.r > 255 - adjust - rgba.r = 255 - else if rgba.r < adjust - rgba.r = 0 - - if rgba.g > 255 - adjust - rgba.g = 255 - else if rgba.g < adjust - rgba.g = 0 - - if rgba.b > 255 - adjust - rgba.b = 255 - else if rgba.b < adjust - rgba.b = 0 - - rgba - -# ## Channels -# Lets you modify the intensity of any combination of red, green, or blue channels individually. -# -# ### Arguments -# Must be given at least one color channel to adjust in order to work. -# Options format (must specify 1 - 3 colors): -#
{
-#   red: 20,
-#   green: -5,
-#   blue: -40
-# }
-Filter.register "channels", (options) -> - return @ if typeof options isnt "object" - - for own chan, value of options - if value is 0 - delete options[chan] - continue - - options[chan] /= 100 - - return @ if options.length is 0 - - @process "channels", (rgba) -> - if options.red? - if options.red > 0 - rgba.r += (255 - rgba.r) * options.red - else - rgba.r -= rgba.r * Math.abs(options.red) - - if options.green? - if options.green > 0 - rgba.g += (255 - rgba.g) * options.green - else - rgba.g -= rgba.g * Math.abs(options.green) - - if options.blue? - if options.blue > 0 - rgba.b += (255 - rgba.b) * options.blue - else - rgba.b -= rgba.b * Math.abs(options.blue) - - rgba - -# ## Curves -# Curves implementation using Bezier curve equation. If you're familiar with the Curves -# functionality in Photoshop, this works in a very similar fashion. -# -# ### Arguments. -#
-#   chan - [r, g, b, rgb]
-#   start - [x, y] (start of curve; 0 - 255)
-#   ctrl1 - [x, y] (control point 1; 0 - 255)
-#   ctrl2 - [x, y] (control point 2; 0 - 255)
-#   end   - [x, y] (end of curve; 0 - 255)
-# 
-# -# The first argument represents the channels you wish to modify with the filter. It can be an -# array of channels or a string (for a single channel). The rest of the arguments are 2-element -# arrays that represent point coordinates. They are specified in the same order as shown in this -# image to the right. The coordinates are in the range of 0 to 255 for both X and Y values. -# -# The x-axis represents the input value for a single channel, while the y-axis represents the -# output value. -Filter.register "curves", (chans, cps...) -> - # If channels are in a string, split to an array - chans = chans.split("") if typeof chans is "string" - chans = ['r', 'g', 'b'] if chans[0] == "v" - - if cps.length < 3 or cps.length > 4 - # might want to give a warning now - throw "Invalid number of arguments to curves filter" - - start = cps[0] - ctrl1 = cps[1] - ctrl2 = if cps.length == 4 then cps[2] else cps[1] - end = cps[cps.length - 1] - - # Generate a bezier curve - bezier = Calculate.bezier start, ctrl1, ctrl2, end, 0, 255 - - # If the curve starts after x = 0, initialize it with a flat line - # until the curve begins. - bezier[i] = start[1] for i in [0...start[0]] if start[0] > 0 - - # ... and the same with the end point - bezier[i] = end[1] for i in [end[0]..255] if end[0] < 255 - - @process "curves", (rgba) -> - # Now that we have the bezier curve, we do a basic hashmap lookup - # to find and replace color values. - rgba[chans[i]] = bezier[rgba[chans[i]]] for i in [0...chans.length] - rgba - -# ## Exposure -# Adjusts the exposure of the image by using the curves function. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will decrease exposure while values > 0 will increase exposure. -Filter.register "exposure", (adjust) -> - p = Math.abs(adjust) / 100 - - ctrl1 = [0, 255 * p] - ctrl2 = [255 - (255 * p), 255] - - if adjust < 0 - ctrl1 = ctrl1.reverse() - ctrl2 = ctrl2.reverse() - - @curves 'rgb', [0, 0], ctrl1, ctrl2, [255, 255] - - - -# Allows us to crop the canvas and produce a new smaller -# canvas. -Caman.Plugin.register "crop", (width, height, x = 0, y = 0) -> - # Create our new canvas element - if exports? - canvas = new Canvas width, height - else - canvas = document.createElement 'canvas' - Util.copyAttributes @canvas, canvas - - canvas.width = width - canvas.height = height - - ctx = canvas.getContext '2d' - - # Perform the cropping by drawing to the new canvas - ctx.drawImage @canvas, x, y, width, height, 0, 0, width, height - - @cropCoordinates = x: x, y: y - - # Update all of the references - @cropped = true - @replaceCanvas canvas - -# Resize the canvas and the image to a new size -Caman.Plugin.register "resize", (newDims = null) -> - # Calculate new size - if newDims is null or (!newDims.width? and !newDims.height?) - Log.error "Invalid or missing dimensions given for resize" - return - - if not newDims.width? - # Calculate width - newDims.width = @canvas.width * newDims.height / @canvas.height - else if not newDims.height? - # Calculate height - newDims.height = @canvas.height * newDims.width / @canvas.width - - if exports? - canvas = new Canvas newDims.width, newDims.height - else - canvas = document.createElement 'canvas' - Util.copyAttributes @canvas, canvas - - canvas.width = newDims.width - canvas.height = newDims.height - - ctx = canvas.getContext '2d' - - ctx.drawImage @canvas, - 0, 0, - @canvas.width, @canvas.height, - 0, 0, - newDims.width, newDims.height - - @resized = true - @replaceCanvas canvas - -Caman.Filter.register "crop", -> - @processPlugin "crop", Array.prototype.slice.call(arguments, 0) - -Caman.Filter.register "resize", -> - @processPlugin "resize", Array.prototype.slice.call(arguments, 0) - -### -IDMC plugins -### - -# resetOriginalPixelData is broken, this is the way it should be - -Caman.Filter.register "idmc_reset_original_pixeldata", () -> - @processPlugin "idmc_reset_original_pixeldata", null - -Caman.Plugin.register "idmc_reset_original_pixeldata", () -> - - Log.debug "idmc_reset_original_pixeldata" - - @originalPixelData = Util.dataArray(@pixelData.length) - @originalPixelData[i] = pixel for pixel, i in @pixelData - @ - -# Adjust minimum and maximim pixel values - -Caman.Filter.register "idmc_set_min_max_pixel_values", (min_pixel_value, max_pixel_value) -> - @processPlugin "idmc_set_min_max_pixel_values", [min_pixel_value, max_pixel_value] - - -Caman.Plugin.register "idmc_set_min_max_pixel_values", (min_pixel_value, max_pixel_value) -> - org_pixels = @originalPixelData - pixels = @pixelData - width = @dimensions.width - height = @dimensions.height - - if not @idmc_set_min_max_pixel_values_r_colormap? - @idmc_set_min_max_pixel_values_r_colormap = (i for i in [0...256]) - - if not @idmc_set_min_max_pixel_values_g_colormap? - @idmc_set_min_max_pixel_values_g_colormap = (i for i in [0...256]) - - if not @idmc_set_min_max_pixel_values_b_colormap? - @idmc_set_min_max_pixel_values_b_colormap = (i for i in [0...256]) - - r_colormap = @idmc_set_min_max_pixel_values_r_colormap - g_colormap = @idmc_set_min_max_pixel_values_g_colormap - b_colormap = @idmc_set_min_max_pixel_values_b_colormap - - - idx = (x,y) => (y*width + x) * 4 - - for i in [0...256] - #Log.debug "i: " +i+ ", " +min_pixel_value+ ", " + "max_pixel_value" - - - index = Math.round((256 * (i - min_pixel_value)) / (max_pixel_value - min_pixel_value)); - #Log.debug "index1: " +index - - index = if index < 0 - 0 - else if i > 255 - 255 - else - index - - #Log.debug "index2: " +index - - r_colormap[i] = if i < min_pixel_value - 0 - else if i > max_pixel_value - 255 - else - index - - g_colormap[i] = if i < min_pixel_value - 0 - else if i > max_pixel_value - 255 - else - index - - b_colormap[i] = if i < min_pixel_value - 0 - else if i > max_pixel_value - 255 - else - index - - - for y in [0...height] - for x in [0...width] - #Log.debug "org_pixels[" +x+ "," +y+ "]: " + org_pixels[idx(x,y)] - - r = org_pixels[idx(x,y)] - g = org_pixels[idx(x,y) + 1] - b = org_pixels[idx(x,y) + 2] - a = org_pixels[idx(x,y) + 3] - - pixels[idx(x,y)] = r_colormap[r] - pixels[idx(x,y) + 1] = g_colormap[g] - pixels[idx(x,y) + 2] = b_colormap[b] - pixels[idx(x,y) + 3] = 255 - - @ - -Caman.Filter.register "idmc_test", () -> - @processPlugin "idmc_test", [] - -Caman.Plugin.register "idmc_test", () -> - @process "idmc_test", (rgba) -> - Log.debug "IDMC test func" - rgba -@ - diff --git a/mig/images/lib/CamanJS-4.1.1/dist/caman.full.js b/mig/images/lib/CamanJS-4.1.1/dist/caman.full.js deleted file mode 100644 index b58ea1f01..000000000 --- a/mig/images/lib/CamanJS-4.1.1/dist/caman.full.js +++ /dev/null @@ -1,2447 +0,0 @@ -// Generated by CoffeeScript 1.6.3 -(function() { - var $, Analyze, Blender, Calculate, Caman, CamanParser, Canvas, Convert, Event, Fiber, Filter, IO, Image, Layer, Log, Logger, PixelInfo, Plugin, Renderer, Root, Store, Util, fs, slice, - __hasProp = {}.hasOwnProperty, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, - __slice = [].slice, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; - - slice = Array.prototype.slice; - - $ = function(sel, root) { - if (root == null) { - root = document; - } - if (typeof sel === "object" || (typeof exports !== "undefined" && exports !== null)) { - return sel; - } - return root.querySelector(sel); - }; - - Util = (function() { - function Util() {} - - Util.uniqid = (function() { - var id; - id = 0; - return { - get: function() { - return id++; - } - }; - })(); - - Util.extend = function(obj) { - var copy, dest, prop, src, _i, _len; - dest = obj; - src = slice.call(arguments, 1); - for (_i = 0, _len = src.length; _i < _len; _i++) { - copy = src[_i]; - for (prop in copy) { - if (!__hasProp.call(copy, prop)) continue; - dest[prop] = copy[prop]; - } - } - return dest; - }; - - Util.clampRGB = function(val) { - if (val < 0) { - return 0; - } - if (val > 255) { - return 255; - } - return val; - }; - - Util.copyAttributes = function(from, to, opts) { - var attr, _i, _len, _ref, _ref1, _results; - if (opts == null) { - opts = {}; - } - _ref = from.attributes; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - attr = _ref[_i]; - if ((opts.except != null) && (_ref1 = attr.nodeName, __indexOf.call(opts.except, _ref1) >= 0)) { - continue; - } - _results.push(to.setAttribute(attr.nodeName, attr.nodeValue)); - } - return _results; - }; - - Util.dataArray = function(length) { - if (length == null) { - length = 0; - } - if (Caman.NodeJS || (window.Uint8Array != null)) { - return new Uint8Array(length); - } - return new Array(length); - }; - - return Util; - - })(); - - if (typeof exports !== "undefined" && exports !== null) { - Root = exports; - Canvas = require('canvas'); - Image = Canvas.Image; - Fiber = require('fibers'); - fs = require('fs'); - } else { - Root = window; - } - - Root.Caman = Caman = (function() { - Caman.version = { - release: "4.1.1", - date: "4/8/2013" - }; - - Caman.DEBUG = false; - - Caman.NodeJS = typeof exports !== "undefined" && exports !== null; - - Caman.autoload = !Caman.NodeJS; - - Caman.allowRevert = true; - - Caman.crossOrigin = "anonymous"; - - Caman.toString = function() { - return "Version " + Caman.version.release + ", Released " + Caman.version.date; - }; - - Caman.remoteProxy = ""; - - Caman.proxyParam = "camanProxyUrl"; - - Caman.getAttrId = function(canvas) { - if (Caman.NodeJS) { - return true; - } - if (typeof canvas === "string") { - canvas = $(canvas); - } - if (!((canvas != null) && (canvas.getAttribute != null))) { - return null; - } - return canvas.getAttribute('data-caman-id'); - }; - - function Caman() { - var args, callback, id, - _this = this; - if (arguments.length === 0) { - throw "Invalid arguments"; - } - if (this instanceof Caman) { - this.finishInit = this.finishInit.bind(this); - this.imageLoaded = this.imageLoaded.bind(this); - args = arguments[0]; - if (!Caman.NodeJS) { - id = parseInt(Caman.getAttrId(args[0]), 10); - callback = typeof args[1] === "function" ? args[1] : typeof args[2] === "function" ? args[2] : function() {}; - if (!isNaN(id) && Store.has(id)) { - return Store.execute(id, callback); - } - } - this.id = Util.uniqid.get(); - this.initializedPixelData = this.originalPixelData = null; - this.cropCoordinates = { - x: 0, - y: 0 - }; - this.cropped = false; - this.resized = false; - this.pixelStack = []; - this.layerStack = []; - this.canvasQueue = []; - this.currentLayer = null; - this.scaled = false; - this.analyze = new Analyze(this); - this.renderer = new Renderer(this); - this.domIsLoaded(function() { - _this.parseArguments(args); - return _this.setup(); - }); - return this; - } else { - return new Caman(arguments); - } - } - - Caman.prototype.domIsLoaded = function(cb) { - var listener, - _this = this; - if (Caman.NodeJS) { - return setTimeout(function() { - return cb.call(_this); - }, 0); - } else { - if (document.readyState === "complete") { - Log.debug("DOM initialized"); - return setTimeout(function() { - return cb.call(_this); - }, 0); - } else { - listener = function() { - if (document.readyState === "complete") { - Log.debug("DOM initialized"); - return cb.call(_this); - } - }; - return document.addEventListener("readystatechange", listener, false); - } - } - }; - - Caman.prototype.parseArguments = function(args) { - var key, val, _ref, _results; - if (args.length === 0) { - throw "Invalid arguments given"; - } - this.initObj = null; - this.initType = null; - this.imageUrl = null; - this.callback = function() {}; - this.setInitObject(args[0]); - if (args.length === 1) { - return; - } - switch (typeof args[1]) { - case "string": - this.imageUrl = args[1]; - break; - case "function": - this.callback = args[1]; - } - if (args.length === 2) { - return; - } - this.callback = args[2]; - if (args.length === 4) { - _ref = args[4]; - _results = []; - for (key in _ref) { - if (!__hasProp.call(_ref, key)) continue; - val = _ref[key]; - _results.push(this.options[key] = val); - } - return _results; - } - }; - - Caman.prototype.setInitObject = function(obj) { - if (Caman.NodeJS) { - this.initObj = obj; - this.initType = 'node'; - return; - } - if (typeof obj === "object") { - this.initObj = obj; - } else { - this.initObj = $(obj); - } - if (this.initObj == null) { - throw "Could not find image or canvas for initialization."; - } - return this.initType = this.initObj.nodeName.toLowerCase(); - }; - - Caman.prototype.setup = function() { - switch (this.initType) { - case "node": - return this.initNode(); - case "img": - return this.initImage(); - case "canvas": - return this.initCanvas(); - } - }; - - Caman.prototype.initNode = function() { - var _this = this; - Log.debug("Initializing for NodeJS"); - this.image = new Image(); - this.image.onload = function() { - Log.debug("Image loaded. Width = " + (_this.imageWidth()) + ", Height = " + (_this.imageHeight())); - _this.canvas = new Canvas(_this.imageWidth(), _this.imageHeight()); - return _this.finishInit(); - }; - this.image.onerror = function(err) { - throw err; - }; - return this.image.src = this.initObj; - }; - - Caman.prototype.initImage = function() { - this.image = this.initObj; - this.canvas = document.createElement('canvas'); - this.context = this.canvas.getContext('2d'); - Util.copyAttributes(this.image, this.canvas, { - except: ['src'] - }); - this.image.parentNode.replaceChild(this.canvas, this.image); - this.imageAdjustments(); - return this.waitForImageLoaded(); - }; - - Caman.prototype.initCanvas = function() { - this.canvas = this.initObj; - this.context = this.canvas.getContext('2d'); - if (this.imageUrl != null) { - this.image = document.createElement('img'); - this.image.src = this.imageUrl; - this.imageAdjustments(); - return this.waitForImageLoaded(); - } else { - return this.finishInit(); - } - }; - - Caman.prototype.imageAdjustments = function() { - if (this.needsHiDPISwap()) { - Log.debug(this.image.src, "->", this.hiDPIReplacement()); - this.swapped = true; - this.image.src = this.hiDPIReplacement(); - } - if (IO.isRemote(this.image)) { - this.image.src = IO.proxyUrl(this.image.src); - return Log.debug("Remote image detected, using URL = " + this.image.src); - } - }; - - Caman.prototype.waitForImageLoaded = function() { - if (this.isImageLoaded()) { - return this.imageLoaded(); - } else { - return this.image.onload = this.imageLoaded; - } - }; - - Caman.prototype.isImageLoaded = function() { - if (!this.image.complete) { - return false; - } - if ((this.image.naturalWidth != null) && this.image.naturalWidth === 0) { - return false; - } - return true; - }; - - Caman.prototype.imageWidth = function() { - return this.image.width || this.image.naturalWidth; - }; - - Caman.prototype.imageHeight = function() { - return this.image.height || this.image.naturalHeight; - }; - - Caman.prototype.imageLoaded = function() { - Log.debug("Image loaded. Width = " + (this.imageWidth()) + ", Height = " + (this.imageHeight())); - if (this.swapped) { - this.canvas.width = this.imageWidth() / this.hiDPIRatio(); - this.canvas.height = this.imageHeight() / this.hiDPIRatio(); - } else { - this.canvas.width = this.imageWidth(); - this.canvas.height = this.imageHeight(); - } - return this.finishInit(); - }; - - Caman.prototype.finishInit = function() { - var i, pixel, _i, _len, _ref; - if (this.context == null) { - this.context = this.canvas.getContext('2d'); - } - this.originalWidth = this.preScaledWidth = this.width = this.canvas.width; - this.originalHeight = this.preScaledHeight = this.height = this.canvas.height; - this.hiDPIAdjustments(); - if (!this.hasId()) { - this.assignId(); - } - if (this.image != null) { - this.context.drawImage(this.image, 0, 0, this.imageWidth(), this.imageHeight(), 0, 0, this.preScaledWidth, this.preScaledHeight); - } - this.reloadCanvasData(); - if (Caman.allowRevert) { - this.initializedPixelData = Util.dataArray(this.pixelData.length); - this.originalPixelData = Util.dataArray(this.pixelData.length); - _ref = this.pixelData; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - pixel = _ref[i]; - this.initializedPixelData[i] = pixel; - this.originalPixelData[i] = pixel; - } - } - this.dimensions = { - width: this.canvas.width, - height: this.canvas.height - }; - Store.put(this.id, this); - this.callback.call(this, this); - return this.callback = function() {}; - }; - - Caman.prototype.reloadCanvasData = function() { - this.imageData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - return this.pixelData = this.imageData.data; - }; - - Caman.prototype.resetOriginalPixelData = function() { - var pixel, _i, _len, _ref, _results; - if (!Caman.allowRevert) { - throw "Revert disabled"; - } - this.originalPixelData = Util.dataArray(this.pixelData.length); - _ref = this.pixelData; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - pixel = _ref[_i]; - _results.push(this.originalPixelData.push(pixel)); - } - return _results; - }; - - Caman.prototype.hasId = function() { - return Caman.getAttrId(this.canvas) != null; - }; - - Caman.prototype.assignId = function() { - if (Caman.NodeJS || this.canvas.getAttribute('data-caman-id')) { - return; - } - return this.canvas.setAttribute('data-caman-id', this.id); - }; - - Caman.prototype.hiDPIDisabled = function() { - return this.canvas.getAttribute('data-caman-hidpi-disabled') !== null; - }; - - Caman.prototype.hiDPIAdjustments = function() { - var ratio; - if (Caman.NodeJS || this.hiDPIDisabled()) { - return; - } - ratio = this.hiDPIRatio(); - if (ratio !== 1) { - Log.debug("HiDPI ratio = " + ratio); - this.scaled = true; - this.preScaledWidth = this.canvas.width; - this.preScaledHeight = this.canvas.height; - this.canvas.width = this.preScaledWidth * ratio; - this.canvas.height = this.preScaledHeight * ratio; - this.canvas.style.width = "" + this.preScaledWidth + "px"; - this.canvas.style.height = "" + this.preScaledHeight + "px"; - this.context.scale(ratio, ratio); - this.width = this.originalWidth = this.canvas.width; - return this.height = this.originalHeight = this.canvas.height; - } - }; - - Caman.prototype.hiDPIRatio = function() { - var backingStoreRatio, devicePixelRatio; - devicePixelRatio = window.devicePixelRatio || 1; - backingStoreRatio = this.context.webkitBackingStorePixelRatio || this.context.mozBackingStorePixelRatio || this.context.msBackingStorePixelRatio || this.context.oBackingStorePixelRatio || this.context.backingStorePixelRatio || 1; - return devicePixelRatio / backingStoreRatio; - }; - - Caman.prototype.hiDPICapable = function() { - return (window.devicePixelRatio != null) && window.devicePixelRatio !== 1; - }; - - Caman.prototype.needsHiDPISwap = function() { - if (this.hiDPIDisabled() || !this.hiDPICapable()) { - return false; - } - return this.hiDPIReplacement() !== null; - }; - - Caman.prototype.hiDPIReplacement = function() { - if (this.image == null) { - return null; - } - return this.image.getAttribute('data-caman-hidpi'); - }; - - Caman.prototype.replaceCanvas = function(newCanvas) { - var oldCanvas; - oldCanvas = this.canvas; - this.canvas = newCanvas; - this.context = this.canvas.getContext('2d'); - oldCanvas.parentNode.replaceChild(this.canvas, oldCanvas); - this.width = this.canvas.width; - this.height = this.canvas.height; - this.reloadCanvasData(); - return this.dimensions = { - width: this.canvas.width, - height: this.canvas.height - }; - }; - - Caman.prototype.render = function(callback) { - var _this = this; - if (callback == null) { - callback = function() {}; - } - Event.trigger(this, "renderStart"); - return this.renderer.execute(function() { - _this.context.putImageData(_this.imageData, 0, 0); - return callback.call(_this); - }); - }; - - Caman.prototype.revert = function() { - var i, pixel, _i, _len, _ref; - if (!Caman.allowRevert) { - throw "Revert disabled"; - } - _ref = this.originalVisiblePixels(); - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - pixel = _ref[i]; - this.pixelData[i] = pixel; - } - return this.context.putImageData(this.imageData, 0, 0); - }; - - Caman.prototype.reset = function() { - var canvas, ctx, i, imageData, pixel, pixelData, _i, _len, _ref; - canvas = document.createElement('canvas'); - Util.copyAttributes(this.canvas, canvas); - canvas.width = this.originalWidth; - canvas.height = this.originalHeight; - ctx = canvas.getContext('2d'); - imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); - pixelData = imageData.data; - _ref = this.initializedPixelData; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - pixel = _ref[i]; - pixelData[i] = pixel; - } - ctx.putImageData(imageData, 0, 0); - this.cropCoordinates = { - x: 0, - y: 0 - }; - this.resized = false; - return this.replaceCanvas(canvas); - }; - - Caman.prototype.originalVisiblePixels = function() { - var canvas, coord, ctx, endX, endY, i, imageData, pixel, pixelData, pixels, scaledCanvas, startX, startY, width, _i, _j, _len, _ref, _ref1, _ref2, _ref3; - if (!Caman.allowRevert) { - throw "Revert disabled"; - } - pixels = []; - startX = this.cropCoordinates.x; - endX = startX + this.width; - startY = this.cropCoordinates.y; - endY = startY + this.height; - if (this.resized) { - canvas = document.createElement('canvas'); - canvas.width = this.originalWidth; - canvas.height = this.originalHeight; - ctx = canvas.getContext('2d'); - imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); - pixelData = imageData.data; - _ref = this.originalPixelData; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - pixel = _ref[i]; - pixelData[i] = pixel; - } - ctx.putImageData(imageData, 0, 0); - scaledCanvas = document.createElement('canvas'); - scaledCanvas.width = this.width; - scaledCanvas.height = this.height; - ctx = scaledCanvas.getContext('2d'); - ctx.drawImage(canvas, 0, 0, this.originalWidth, this.originalHeight, 0, 0, this.width, this.height); - pixelData = ctx.getImageData(0, 0, this.width, this.height).data; - width = this.width; - } else { - pixelData = this.originalPixelData; - width = this.originalWidth; - } - for (i = _j = 0, _ref1 = pixelData.length; _j < _ref1; i = _j += 4) { - coord = PixelInfo.locationToCoordinates(i, width); - if (((startX <= (_ref2 = coord.x) && _ref2 < endX)) && ((startY <= (_ref3 = coord.y) && _ref3 < endY))) { - pixels.push(pixelData[i], pixelData[i + 1], pixelData[i + 2], pixelData[i + 3]); - } - } - return pixels; - }; - - Caman.prototype.process = function(name, processFn) { - this.renderer.add({ - type: Filter.Type.Single, - name: name, - processFn: processFn - }); - return this; - }; - - Caman.prototype.processKernel = function(name, adjust, divisor, bias) { - var i, _i, _ref; - if (!divisor) { - divisor = 0; - for (i = _i = 0, _ref = adjust.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - divisor += adjust[i]; - } - } - this.renderer.add({ - type: Filter.Type.Kernel, - name: name, - adjust: adjust, - divisor: divisor, - bias: bias || 0 - }); - return this; - }; - - Caman.prototype.processPlugin = function(plugin, args) { - this.renderer.add({ - type: Filter.Type.Plugin, - plugin: plugin, - args: args - }); - return this; - }; - - Caman.prototype.newLayer = function(callback) { - var layer; - layer = new Layer(this); - this.canvasQueue.push(layer); - this.renderer.add({ - type: Filter.Type.LayerDequeue - }); - callback.call(layer); - this.renderer.add({ - type: Filter.Type.LayerFinished - }); - return this; - }; - - Caman.prototype.executeLayer = function(layer) { - return this.pushContext(layer); - }; - - Caman.prototype.pushContext = function(layer) { - this.layerStack.push(this.currentLayer); - this.pixelStack.push(this.pixelData); - this.currentLayer = layer; - return this.pixelData = layer.pixelData; - }; - - Caman.prototype.popContext = function() { - this.pixelData = this.pixelStack.pop(); - return this.currentLayer = this.layerStack.pop(); - }; - - Caman.prototype.applyCurrentLayer = function() { - return this.currentLayer.applyToParent(); - }; - - return Caman; - - })(); - - Analyze = (function() { - function Analyze(c) { - this.c = c; - } - - Analyze.prototype.calculateLevels = function() { - var i, levels, numPixels, _i, _j, _k, _ref; - levels = { - r: {}, - g: {}, - b: {} - }; - for (i = _i = 0; _i <= 255; i = ++_i) { - levels.r[i] = 0; - levels.g[i] = 0; - levels.b[i] = 0; - } - for (i = _j = 0, _ref = this.c.pixelData.length; _j < _ref; i = _j += 4) { - levels.r[this.c.pixelData[i]]++; - levels.g[this.c.pixelData[i + 1]]++; - levels.b[this.c.pixelData[i + 2]]++; - } - numPixels = this.c.pixelData.length / 4; - for (i = _k = 0; _k <= 255; i = ++_k) { - levels.r[i] /= numPixels; - levels.g[i] /= numPixels; - levels.b[i] /= numPixels; - } - return levels; - }; - - return Analyze; - - })(); - - Caman.DOMUpdated = function() { - var img, imgs, parser, _i, _len, _results; - imgs = document.querySelectorAll("img[data-caman]"); - if (!(imgs.length > 0)) { - return; - } - _results = []; - for (_i = 0, _len = imgs.length; _i < _len; _i++) { - img = imgs[_i]; - _results.push(parser = new CamanParser(img, function() { - this.parse(); - return this.execute(); - })); - } - return _results; - }; - - if (Caman.autoload) { - (function() { - if (document.readyState === "complete") { - return Caman.DOMUpdated(); - } else { - return document.addEventListener("DOMContentLoaded", Caman.DOMUpdated, false); - } - })(); - } - - CamanParser = (function() { - var INST_REGEX; - - INST_REGEX = "(\\w+)\\((.*?)\\)"; - - function CamanParser(ele, ready) { - this.dataStr = ele.getAttribute('data-caman'); - this.caman = Caman(ele, ready.bind(this)); - } - - CamanParser.prototype.parse = function() { - var args, e, filter, func, inst, instFunc, m, r, unparsedInstructions, _i, _len, _ref, _results; - this.ele = this.caman.canvas; - r = new RegExp(INST_REGEX, 'g'); - unparsedInstructions = this.dataStr.match(r); - if (!(unparsedInstructions.length > 0)) { - return; - } - r = new RegExp(INST_REGEX); - _results = []; - for (_i = 0, _len = unparsedInstructions.length; _i < _len; _i++) { - inst = unparsedInstructions[_i]; - _ref = inst.match(r), m = _ref[0], filter = _ref[1], args = _ref[2]; - instFunc = new Function("return function() { this." + filter + "(" + args + "); };"); - try { - func = instFunc(); - _results.push(func.call(this.caman)); - } catch (_error) { - e = _error; - _results.push(Log.debug(e)); - } - } - return _results; - }; - - CamanParser.prototype.execute = function() { - var ele; - ele = this.ele; - return this.caman.render(function() { - return ele.parentNode.replaceChild(this.toImage(), ele); - }); - }; - - return CamanParser; - - })(); - - Caman.Blender = Blender = (function() { - function Blender() {} - - Blender.blenders = {}; - - Blender.register = function(name, func) { - return this.blenders[name] = func; - }; - - Blender.execute = function(name, rgbaLayer, rgbaParent) { - return this.blenders[name](rgbaLayer, rgbaParent); - }; - - return Blender; - - })(); - - Caman.Calculate = Calculate = (function() { - function Calculate() {} - - Calculate.distance = function(x1, y1, x2, y2) { - return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); - }; - - Calculate.randomRange = function(min, max, getFloat) { - var rand; - if (getFloat == null) { - getFloat = false; - } - rand = min + (Math.random() * (max - min)); - if (getFloat) { - return rand.toFixed(getFloat); - } else { - return Math.round(rand); - } - }; - - Calculate.luminance = function(rgba) { - return (0.299 * rgba.r) + (0.587 * rgba.g) + (0.114 * rgba.b); - }; - - Calculate.bezier = function(start, ctrl1, ctrl2, end, lowBound, highBound) { - var Ax, Ay, Bx, By, Cx, Cy, bezier, curveX, curveY, i, j, leftCoord, rightCoord, t, x0, x1, x2, x3, y0, y1, y2, y3, _i, _j, _k, _ref, _ref1; - x0 = start[0]; - y0 = start[1]; - x1 = ctrl1[0]; - y1 = ctrl1[1]; - x2 = ctrl2[0]; - y2 = ctrl2[1]; - x3 = end[0]; - y3 = end[1]; - bezier = {}; - Cx = parseInt(3 * (x1 - x0), 10); - Bx = 3 * (x2 - x1) - Cx; - Ax = x3 - x0 - Cx - Bx; - Cy = 3 * (y1 - y0); - By = 3 * (y2 - y1) - Cy; - Ay = y3 - y0 - Cy - By; - for (i = _i = 0; _i < 1000; i = ++_i) { - t = i / 1000; - curveX = Math.round((Ax * Math.pow(t, 3)) + (Bx * Math.pow(t, 2)) + (Cx * t) + x0); - curveY = Math.round((Ay * Math.pow(t, 3)) + (By * Math.pow(t, 2)) + (Cy * t) + y0); - if (lowBound && curveY < lowBound) { - curveY = lowBound; - } else if (highBound && curveY > highBound) { - curveY = highBound; - } - bezier[curveX] = curveY; - } - if (bezier.length < end[0] + 1) { - for (i = _j = 0, _ref = end[0]; 0 <= _ref ? _j <= _ref : _j >= _ref; i = 0 <= _ref ? ++_j : --_j) { - if (bezier[i] == null) { - leftCoord = [i - 1, bezier[i - 1]]; - for (j = _k = i, _ref1 = end[0]; i <= _ref1 ? _k <= _ref1 : _k >= _ref1; j = i <= _ref1 ? ++_k : --_k) { - if (bezier[j] != null) { - rightCoord = [j, bezier[j]]; - break; - } - } - bezier[i] = leftCoord[1] + ((rightCoord[1] - leftCoord[1]) / (rightCoord[0] - leftCoord[0])) * (i - leftCoord[0]); - } - } - } - if (bezier[end[0]] == null) { - bezier[end[0]] = bezier[end[0] - 1]; - } - return bezier; - }; - - return Calculate; - - })(); - - Convert = (function() { - function Convert() {} - - Convert.hexToRGB = function(hex) { - var b, g, r; - if (hex.charAt(0) === "#") { - hex = hex.substr(1); - } - r = parseInt(hex.substr(0, 2), 16); - g = parseInt(hex.substr(2, 2), 16); - b = parseInt(hex.substr(4, 2), 16); - return { - r: r, - g: g, - b: b - }; - }; - - Convert.rgbToHSL = function(r, g, b) { - var d, h, l, max, min, s; - if (typeof r === "object") { - g = r.g; - b = r.b; - r = r.r; - } - r /= 255; - g /= 255; - b /= 255; - max = Math.max(r, g, b); - min = Math.min(r, g, b); - l = (max + min) / 2; - if (max === min) { - h = s = 0; - } else { - d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - h = (function() { - switch (max) { - case r: - return (g - b) / d + (g < b ? 6 : 0); - case g: - return (b - r) / d + 2; - case b: - return (r - g) / d + 4; - } - })(); - h /= 6; - } - return { - h: h, - s: s, - l: l - }; - }; - - Convert.hslToRGB = function(h, s, l) { - var b, g, p, q, r; - if (typeof h === "object") { - s = h.s; - l = h.l; - h = h.h; - } - if (s === 0) { - r = g = b = l; - } else { - q = l < 0.5 ? l * (1 + s) : l + s - l * s; - p = 2 * l - q; - r = this.hueToRGB(p, q, h + 1 / 3); - g = this.hueToRGB(p, q, h); - b = this.hueToRGB(p, q, h - 1 / 3); - } - return { - r: r * 255, - g: g * 255, - b: b * 255 - }; - }; - - Convert.hueToRGB = function(p, q, t) { - if (t < 0) { - t += 1; - } - if (t > 1) { - t -= 1; - } - if (t < 1 / 6) { - return p + (q - p) * 6 * t; - } - if (t < 1 / 2) { - return q; - } - if (t < 2 / 3) { - return p + (q - p) * (2 / 3 - t) * 6; - } - return p; - }; - - Convert.rgbToHSV = function(r, g, b) { - var d, h, max, min, s, v; - r /= 255; - g /= 255; - b /= 255; - max = Math.max(r, g, b); - min = Math.min(r, g, b); - v = max; - d = max - min; - s = max === 0 ? 0 : d / max; - if (max === min) { - h = 0; - } else { - h = (function() { - switch (max) { - case r: - return (g - b) / d + (g < b ? 6 : 0); - case g: - return (b - r) / d + 2; - case b: - return (r - g) / d + 4; - } - })(); - h /= 6; - } - return { - h: h, - s: s, - v: v - }; - }; - - Convert.hsvToRGB = function(h, s, v) { - var b, f, g, i, p, q, r, t; - i = Math.floor(h * 6); - f = h * 6 - i; - p = v * (1 - s); - q = v * (1 - f * s); - t = v * (1 - (1 - f) * s); - switch (i % 6) { - case 0: - r = v; - g = t; - b = p; - break; - case 1: - r = q; - g = v; - b = p; - break; - case 2: - r = p; - g = v; - b = t; - break; - case 3: - r = p; - g = q; - b = v; - break; - case 4: - r = t; - g = p; - b = v; - break; - case 5: - r = v; - g = p; - b = q; - } - return { - r: r * 255, - g: g * 255, - b: b * 255 - }; - }; - - Convert.rgbToXYZ = function(r, g, b) { - var x, y, z; - r /= 255; - g /= 255; - b /= 255; - if (r > 0.04045) { - r = Math.pow((r + 0.055) / 1.055, 2.4); - } else { - r /= 12.92; - } - if (g > 0.04045) { - g = Math.pow((g + 0.055) / 1.055, 2.4); - } else { - g /= 12.92; - } - if (b > 0.04045) { - b = Math.pow((b + 0.055) / 1.055, 2.4); - } else { - b /= 12.92; - } - x = r * 0.4124 + g * 0.3576 + b * 0.1805; - y = r * 0.2126 + g * 0.7152 + b * 0.0722; - z = r * 0.0193 + g * 0.1192 + b * 0.9505; - return { - x: x * 100, - y: y * 100, - z: z * 100 - }; - }; - - Convert.xyzToRGB = function(x, y, z) { - var b, g, r; - x /= 100; - y /= 100; - z /= 100; - r = (3.2406 * x) + (-1.5372 * y) + (-0.4986 * z); - g = (-0.9689 * x) + (1.8758 * y) + (0.0415 * z); - b = (0.0557 * x) + (-0.2040 * y) + (1.0570 * z); - if (r > 0.0031308) { - r = (1.055 * Math.pow(r, 0.4166666667)) - 0.055; - } else { - r *= 12.92; - } - if (g > 0.0031308) { - g = (1.055 * Math.pow(g, 0.4166666667)) - 0.055; - } else { - g *= 12.92; - } - if (b > 0.0031308) { - b = (1.055 * Math.pow(b, 0.4166666667)) - 0.055; - } else { - b *= 12.92; - } - return { - r: r * 255, - g: g * 255, - b: b * 255 - }; - }; - - Convert.xyzToLab = function(x, y, z) { - var a, b, l, whiteX, whiteY, whiteZ; - if (typeof x === "object") { - y = x.y; - z = x.z; - x = x.x; - } - whiteX = 95.047; - whiteY = 100.0; - whiteZ = 108.883; - x /= whiteX; - y /= whiteY; - z /= whiteZ; - if (x > 0.008856451679) { - x = Math.pow(x, 0.3333333333); - } else { - x = (7.787037037 * x) + 0.1379310345; - } - if (y > 0.008856451679) { - y = Math.pow(y, 0.3333333333); - } else { - y = (7.787037037 * y) + 0.1379310345; - } - if (z > 0.008856451679) { - z = Math.pow(z, 0.3333333333); - } else { - z = (7.787037037 * z) + 0.1379310345; - } - l = 116 * y - 16; - a = 500 * (x - y); - b = 200 * (y - z); - return { - l: l, - a: a, - b: b - }; - }; - - Convert.labToXYZ = function(l, a, b) { - var x, y, z; - if (typeof l === "object") { - a = l.a; - b = l.b; - l = l.l; - } - y = (l + 16) / 116; - x = y + (a / 500); - z = y - (b / 200); - if (x > 0.2068965517) { - x = x * x * x; - } else { - x = 0.1284185493 * (x - 0.1379310345); - } - if (y > 0.2068965517) { - y = y * y * y; - } else { - y = 0.1284185493 * (y - 0.1379310345); - } - if (z > 0.2068965517) { - z = z * z * z; - } else { - z = 0.1284185493 * (z - 0.1379310345); - } - return { - x: x * 95.047, - y: y * 100.0, - z: z * 108.883 - }; - }; - - Convert.rgbToLab = function(r, g, b) { - var xyz; - if (typeof r === "object") { - g = r.g; - b = r.b; - r = r.r; - } - xyz = this.rgbToXYZ(r, g, b); - return this.xyzToLab(xyz); - }; - - Convert.labToRGB = function(l, a, b) {}; - - return Convert; - - })(); - - Event = (function() { - function Event() {} - - Event.events = {}; - - Event.types = ["processStart", "processComplete", "renderStart", "renderFinished", "blockStarted", "blockFinished"]; - - Event.trigger = function(target, type, data) { - var event, _i, _len, _ref, _results; - if (this.events[type] && this.events[type].length) { - _ref = this.events[type]; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - event = _ref[_i]; - if (event.target === null || target.id === event.target.id) { - _results.push(event.fn.call(target, data)); - } else { - _results.push(void 0); - } - } - return _results; - } - }; - - Event.listen = function(target, type, fn) { - var _fn, _type; - if (typeof target === "string") { - _type = target; - _fn = type; - target = null; - type = _type; - fn = _fn; - } - if (__indexOf.call(this.types, type) < 0) { - return false; - } - if (!this.events[type]) { - this.events[type] = []; - } - this.events[type].push({ - target: target, - fn: fn - }); - return true; - }; - - return Event; - - })(); - - Caman.Event = Event; - - Caman.Filter = Filter = (function() { - function Filter() {} - - Filter.Type = { - Single: 1, - Kernel: 2, - LayerDequeue: 3, - LayerFinished: 4, - LoadOverlay: 5, - Plugin: 6 - }; - - Filter.register = function(name, filterFunc) { - return Caman.prototype[name] = filterFunc; - }; - - return Filter; - - })(); - - Caman.IO = IO = (function() { - function IO() {} - - IO.domainRegex = /(?:(?:http|https):\/\/)((?:\w+)\.(?:(?:\w|\.)+))/; - - IO.isRemote = function(img) { - if (img == null) { - return false; - } - if (this.corsEnabled(img)) { - return false; - } - return this.isURLRemote(img.src); - }; - - IO.corsEnabled = function(img) { - var _ref; - return (img.crossOrigin != null) && ((_ref = img.crossOrigin.toLowerCase()) === 'anonymous' || _ref === 'use-credentials'); - }; - - IO.isURLRemote = function(url) { - var matches; - matches = url.match(this.domainRegex); - if (matches) { - return matches[1] !== document.domain; - } else { - return false; - } - }; - - IO.remoteCheck = function(src) { - if (this.isURLRemote(src)) { - if (!Caman.remoteProxy.length) { - Log.info("Attempting to load a remote image without a configured proxy. URL: " + src); - } else { - if (Caman.isURLRemote(Caman.remoteProxy)) { - Log.info("Cannot use a remote proxy for loading images."); - return; - } - return "" + Caman.remoteProxy + "?camanProxyUrl=" + (encodeURIComponent(src)); - } - } - }; - - IO.proxyUrl = function(src) { - return "" + Caman.remoteProxy + "?" + Caman.proxyParam + "=" + (encodeURIComponent(src)); - }; - - IO.useProxy = function(lang) { - var langToExt; - langToExt = { - ruby: 'rb', - python: 'py', - perl: 'pl', - javascript: 'js' - }; - lang = lang.toLowerCase(); - if (langToExt[lang] != null) { - lang = langToExt[lang]; - } - return "proxies/caman_proxy." + lang; - }; - - return IO; - - })(); - - Caman.prototype.save = function() { - if (typeof exports !== "undefined" && exports !== null) { - return this.nodeSave.apply(this, arguments); - } else { - return this.browserSave.apply(this, arguments); - } - }; - - Caman.prototype.browserSave = function(type) { - var image; - if (type == null) { - type = "png"; - } - type = type.toLowerCase(); - image = this.toBase64(type).replace("image/" + type, "image/octet-stream"); - return document.location.href = image; - }; - - Caman.prototype.nodeSave = function(file, overwrite) { - var e, stats; - if (overwrite == null) { - overwrite = true; - } - try { - stats = fs.statSync(file); - if (stats.isFile() && !overwrite) { - return false; - } - } catch (_error) { - e = _error; - Log.debug("Creating output file " + file); - } - return fs.writeFile(file, this.canvas.toBuffer(), function() { - return Log.debug("Finished writing to " + file); - }); - }; - - Caman.prototype.toImage = function(type) { - var img; - img = document.createElement('img'); - img.src = this.toBase64(type); - img.width = this.dimensions.width; - img.height = this.dimensions.height; - if (window.devicePixelRatio) { - img.width /= window.devicePixelRatio; - img.height /= window.devicePixelRatio; - } - return img; - }; - - Caman.prototype.toBase64 = function(type) { - if (type == null) { - type = "png"; - } - type = type.toLowerCase(); - return this.canvas.toDataURL("image/" + type); - }; - - Layer = (function() { - function Layer(c) { - this.c = c; - this.filter = this.c; - this.options = { - blendingMode: 'normal', - opacity: 1.0 - }; - this.layerID = Util.uniqid.get(); - this.canvas = typeof exports !== "undefined" && exports !== null ? new Canvas() : document.createElement('canvas'); - this.canvas.width = this.c.dimensions.width; - this.canvas.height = this.c.dimensions.height; - this.context = this.canvas.getContext('2d'); - this.context.createImageData(this.canvas.width, this.canvas.height); - this.imageData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - this.pixelData = this.imageData.data; - } - - Layer.prototype.newLayer = function(cb) { - return this.c.newLayer.call(this.c, cb); - }; - - Layer.prototype.setBlendingMode = function(mode) { - this.options.blendingMode = mode; - return this; - }; - - Layer.prototype.opacity = function(opacity) { - this.options.opacity = opacity / 100; - return this; - }; - - Layer.prototype.copyParent = function() { - var i, parentData, _i, _ref; - parentData = this.c.pixelData; - for (i = _i = 0, _ref = this.c.pixelData.length; _i < _ref; i = _i += 4) { - this.pixelData[i] = parentData[i]; - this.pixelData[i + 1] = parentData[i + 1]; - this.pixelData[i + 2] = parentData[i + 2]; - this.pixelData[i + 3] = parentData[i + 3]; - } - return this; - }; - - Layer.prototype.fillColor = function() { - return this.c.fillColor.apply(this.c, arguments); - }; - - Layer.prototype.overlayImage = function(image) { - if (typeof image === "object") { - image = image.src; - } else if (typeof image === "string" && image[0] === "#") { - image = $(image).src; - } - if (!image) { - return this; - } - this.c.renderer.renderQueue.push({ - type: Filter.Type.LoadOverlay, - src: image, - layer: this - }); - return this; - }; - - Layer.prototype.applyToParent = function() { - var i, layerData, parentData, result, rgbaLayer, rgbaParent, _i, _ref, _results; - parentData = this.c.pixelStack[this.c.pixelStack.length - 1]; - layerData = this.c.pixelData; - _results = []; - for (i = _i = 0, _ref = layerData.length; _i < _ref; i = _i += 4) { - rgbaParent = { - r: parentData[i], - g: parentData[i + 1], - b: parentData[i + 2], - a: parentData[i + 3] - }; - rgbaLayer = { - r: layerData[i], - g: layerData[i + 1], - b: layerData[i + 2], - a: layerData[i + 3] - }; - result = Blender.execute(this.options.blendingMode, rgbaLayer, rgbaParent); - result.r = Util.clampRGB(result.r); - result.g = Util.clampRGB(result.g); - result.b = Util.clampRGB(result.b); - if (result.a == null) { - result.a = rgbaLayer.a; - } - parentData[i] = rgbaParent.r - ((rgbaParent.r - result.r) * (this.options.opacity * (result.a / 255))); - parentData[i + 1] = rgbaParent.g - ((rgbaParent.g - result.g) * (this.options.opacity * (result.a / 255))); - _results.push(parentData[i + 2] = rgbaParent.b - ((rgbaParent.b - result.b) * (this.options.opacity * (result.a / 255)))); - } - return _results; - }; - - return Layer; - - })(); - - Logger = (function() { - function Logger() { - var name, _i, _len, _ref; - _ref = ['log', 'info', 'warn', 'error']; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - name = _ref[_i]; - this[name] = (function(name) { - return function() { - var args, e; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - if (!Caman.DEBUG) { - return; - } - try { - return console[name].apply(console, args); - } catch (_error) { - e = _error; - return console[name](args); - } - }; - })(name); - } - this.debug = this.log; - } - - return Logger; - - })(); - - Log = new Logger(); - - PixelInfo = (function() { - PixelInfo.coordinatesToLocation = function(x, y, width) { - return (y * width + x) * 4; - }; - - PixelInfo.locationToCoordinates = function(loc, width) { - var x, y; - y = Math.floor(loc / (width * 4)); - x = (loc % (width * 4)) / 4; - return { - x: x, - y: y - }; - }; - - function PixelInfo(c) { - this.c = c; - this.loc = 0; - } - - PixelInfo.prototype.locationXY = function() { - var x, y; - y = this.c.dimensions.height - Math.floor(this.loc / (this.c.dimensions.width * 4)); - x = (this.loc % (this.c.dimensions.width * 4)) / 4; - return { - x: x, - y: y - }; - }; - - PixelInfo.prototype.getPixelRelative = function(horiz, vert) { - var newLoc; - newLoc = this.loc + (this.c.dimensions.width * 4 * (vert * -1)) + (4 * horiz); - if (newLoc > this.c.pixelData.length || newLoc < 0) { - return { - r: 0, - g: 0, - b: 0, - a: 0 - }; - } - return { - r: this.c.pixelData[newLoc], - g: this.c.pixelData[newLoc + 1], - b: this.c.pixelData[newLoc + 2], - a: this.c.pixelData[newLoc + 3] - }; - }; - - PixelInfo.prototype.putPixelRelative = function(horiz, vert, rgba) { - var nowLoc; - nowLoc = this.loc + (this.c.dimensions.width * 4 * (vert * -1)) + (4 * horiz); - if (newLoc > this.c.pixelData.length || newLoc < 0) { - return; - } - this.c.pixelData[newLoc] = rgba.r; - this.c.pixelData[newLoc + 1] = rgba.g; - this.c.pixelData[newLoc + 2] = rgba.b; - this.c.pixelData[newLoc + 3] = rgba.a; - return true; - }; - - PixelInfo.prototype.getPixel = function(x, y) { - var loc; - loc = this.coordinatesToLocation(x, y, this.width); - return { - r: this.c.pixelData[loc], - g: this.c.pixelData[loc + 1], - b: this.c.pixelData[loc + 2], - a: this.c.pixelData[loc + 3] - }; - }; - - PixelInfo.prototype.putPixel = function(x, y, rgba) { - var loc; - loc = this.coordinatesToLocation(x, y, this.width); - this.c.pixelData[loc] = rgba.r; - this.c.pixelData[loc + 1] = rgba.g; - this.c.pixelData[loc + 2] = rgba.b; - return this.c.pixelData[loc + 3] = rgba.a; - }; - - return PixelInfo; - - })(); - - Plugin = (function() { - function Plugin() {} - - Plugin.plugins = {}; - - Plugin.register = function(name, plugin) { - return this.plugins[name] = plugin; - }; - - Plugin.execute = function(context, name, args) { - return this.plugins[name].apply(context, args); - }; - - return Plugin; - - })(); - - Caman.Plugin = Plugin; - - Caman.Renderer = Renderer = (function() { - Renderer.Blocks = Caman.NodeJS ? require('os').cpus().length : 4; - - function Renderer(c) { - this.c = c; - this.processNext = __bind(this.processNext, this); - this.renderQueue = []; - this.modPixelData = null; - } - - Renderer.prototype.add = function(job) { - if (job == null) { - return; - } - return this.renderQueue.push(job); - }; - - Renderer.prototype.processNext = function() { - var layer; - if (this.renderQueue.length === 0) { - Event.trigger(this, "renderFinished"); - if (this.finishedFn != null) { - this.finishedFn.call(this.c); - } - return this; - } - this.currentJob = this.renderQueue.shift(); - switch (this.currentJob.type) { - case Filter.Type.LayerDequeue: - layer = this.c.canvasQueue.shift(); - this.c.executeLayer(layer); - return this.processNext(); - case Filter.Type.LayerFinished: - this.c.applyCurrentLayer(); - this.c.popContext(); - return this.processNext(); - case Filter.Type.LoadOverlay: - return this.loadOverlay(this.currentJob.layer, this.currentJob.src); - case Filter.Type.Plugin: - return this.executePlugin(); - default: - return this.executeFilter(); - } - }; - - Renderer.prototype.execute = function(callback) { - this.finishedFn = callback; - this.modPixelData = Util.dataArray(this.c.pixelData.length); - return this.processNext(); - }; - - Renderer.prototype.eachBlock = function(fn) { - var blockN, blockPixelLength, bnum, end, f, i, lastBlockN, n, start, _i, _ref, _results, - _this = this; - this.blocksDone = 0; - n = this.c.pixelData.length; - blockPixelLength = Math.floor((n / 4) / Renderer.Blocks); - blockN = blockPixelLength * 4; - lastBlockN = blockN + ((n / 4) % Renderer.Blocks) * 4; - _results = []; - for (i = _i = 0, _ref = Renderer.Blocks; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - start = i * blockN; - end = start + (i === Renderer.Blocks - 1 ? lastBlockN : blockN); - if (Caman.NodeJS) { - f = Fiber(function() { - return fn.call(_this, i, start, end); - }); - bnum = f.run(); - _results.push(this.blockFinished(bnum)); - } else { - _results.push(setTimeout((function(i, start, end) { - return function() { - return fn.call(_this, i, start, end); - }; - })(i, start, end), 0)); - } - } - return _results; - }; - - Renderer.prototype.executeFilter = function() { - Event.trigger(this.c, "processStart", this.currentJob); - if (this.currentJob.type === Filter.Type.Single) { - return this.eachBlock(this.renderBlock); - } else { - return this.eachBlock(this.renderKernel); - } - }; - - Renderer.prototype.executePlugin = function() { - Log.debug("Executing plugin " + this.currentJob.plugin); - Plugin.execute(this.c, this.currentJob.plugin, this.currentJob.args); - Log.debug("Plugin " + this.currentJob.plugin + " finished!"); - return this.processNext(); - }; - - Renderer.prototype.renderBlock = function(bnum, start, end) { - var data, i, pixelInfo, res, _i; - Log.debug("Block #" + bnum + " - Filter: " + this.currentJob.name + ", Start: " + start + ", End: " + end); - Event.trigger(this.c, "blockStarted", { - blockNum: bnum, - totalBlocks: Renderer.Blocks, - startPixel: start, - endPixel: end - }); - data = { - r: 0, - g: 0, - b: 0, - a: 0 - }; - pixelInfo = new PixelInfo(this.c); - for (i = _i = start; _i < end; i = _i += 4) { - pixelInfo.loc = i; - data.r = this.c.pixelData[i]; - data.g = this.c.pixelData[i + 1]; - data.b = this.c.pixelData[i + 2]; - data.a = this.c.pixelData[i + 3]; - res = this.currentJob.processFn.call(pixelInfo, data); - if (res.a == null) { - res.a = data.a; - } - this.c.pixelData[i] = Util.clampRGB(res.r); - this.c.pixelData[i + 1] = Util.clampRGB(res.g); - this.c.pixelData[i + 2] = Util.clampRGB(res.b); - this.c.pixelData[i + 3] = Util.clampRGB(res.a); - } - if (Caman.NodeJS) { - return Fiber["yield"](bnum); - } else { - return this.blockFinished(bnum); - } - }; - - Renderer.prototype.renderKernel = function(bnum, start, end) { - var adjust, adjustSize, bias, builder, builderIndex, divisor, i, j, k, kernel, n, name, pixel, pixelInfo, res, _i, _j, _k; - name = this.currentJob.name; - bias = this.currentJob.bias; - divisor = this.currentJob.divisor; - n = this.c.pixelData.length; - adjust = this.currentJob.adjust; - adjustSize = Math.sqrt(adjust.length); - kernel = []; - Log.debug("Rendering kernel - Filter: " + this.currentJob.name); - start = Math.max(start, this.c.dimensions.width * 4 * ((adjustSize - 1) / 2)); - end = Math.min(end, n - (this.c.dimensions.width * 4 * ((adjustSize - 1) / 2))); - builder = (adjustSize - 1) / 2; - pixelInfo = new PixelInfo(this.c); - for (i = _i = start; _i < end; i = _i += 4) { - pixelInfo.loc = i; - builderIndex = 0; - for (j = _j = -builder; -builder <= builder ? _j <= builder : _j >= builder; j = -builder <= builder ? ++_j : --_j) { - for (k = _k = builder; builder <= -builder ? _k <= -builder : _k >= -builder; k = builder <= -builder ? ++_k : --_k) { - pixel = pixelInfo.getPixelRelative(j, k); - kernel[builderIndex * 3] = pixel.r; - kernel[builderIndex * 3 + 1] = pixel.g; - kernel[builderIndex * 3 + 2] = pixel.b; - builderIndex++; - } - } - res = this.processKernel(adjust, kernel, divisor, bias); - this.modPixelData[i] = Util.clampRGB(res.r); - this.modPixelData[i + 1] = Util.clampRGB(res.g); - this.modPixelData[i + 2] = Util.clampRGB(res.b); - this.modPixelData[i + 3] = this.c.pixelData[i + 3]; - } - if (Caman.NodeJS) { - return Fiber["yield"](bnum); - } else { - return this.blockFinished(bnum); - } - }; - - Renderer.prototype.blockFinished = function(bnum) { - var i, _i, _ref; - if (bnum >= 0) { - Log.debug("Block #" + bnum + " finished! Filter: " + this.currentJob.name); - } - this.blocksDone++; - Event.trigger(this.c, "blockFinished", { - blockNum: bnum, - blocksFinished: this.blocksDone, - totalBlocks: Renderer.Blocks - }); - if (this.blocksDone === Renderer.Blocks) { - if (this.currentJob.type === Filter.Type.Kernel) { - for (i = _i = 0, _ref = this.c.pixelData.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - this.c.pixelData[i] = this.modPixelData[i]; - } - } - if (bnum >= 0) { - Log.debug("Filter " + this.currentJob.name + " finished!"); - } - Event.trigger(this.c, "processComplete", this.currentJob); - return this.processNext(); - } - }; - - Renderer.prototype.processKernel = function(adjust, kernel, divisor, bias) { - var i, val, _i, _ref; - val = { - r: 0, - g: 0, - b: 0 - }; - for (i = _i = 0, _ref = adjust.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - val.r += adjust[i] * kernel[i * 3]; - val.g += adjust[i] * kernel[i * 3 + 1]; - val.b += adjust[i] * kernel[i * 3 + 2]; - } - val.r = (val.r / divisor) + bias; - val.g = (val.g / divisor) + bias; - val.b = (val.b / divisor) + bias; - return val; - }; - - Renderer.prototype.loadOverlay = function(layer, src) { - var img, proxyUrl, - _this = this; - img = document.createElement('img'); - img.onload = function() { - layer.context.drawImage(img, 0, 0, _this.c.dimensions.width, _this.c.dimensions.height); - layer.imageData = layer.context.getImageData(0, 0, _this.c.dimensions.width, _this.c.dimensions.height); - layer.pixelData = layer.imageData.data; - _this.c.pixelData = layer.pixelData; - return _this.processNext(); - }; - proxyUrl = IO.remoteCheck(src); - return img.src = proxyUrl != null ? proxyUrl : src; - }; - - return Renderer; - - })(); - - Caman.Store = Store = (function() { - function Store() {} - - Store.items = {}; - - Store.has = function(search) { - return this.items[search] != null; - }; - - Store.get = function(search) { - return this.items[search]; - }; - - Store.put = function(name, obj) { - return this.items[name] = obj; - }; - - Store.execute = function(search, callback) { - var _this = this; - setTimeout(function() { - return callback.call(_this.get(search), _this.get(search)); - }, 0); - return this.get(search); - }; - - Store.flush = function(name) { - if (name == null) { - name = false; - } - if (name) { - return delete this.items[name]; - } else { - return this.items = {}; - } - }; - - return Store; - - })(); - - Blender.register("normal", function(rgbaLayer, rgbaParent) { - return { - r: rgbaLayer.r, - g: rgbaLayer.g, - b: rgbaLayer.b - }; - }); - - Blender.register("multiply", function(rgbaLayer, rgbaParent) { - return { - r: (rgbaLayer.r * rgbaParent.r) / 255, - g: (rgbaLayer.g * rgbaParent.g) / 255, - b: (rgbaLayer.b * rgbaParent.b) / 255 - }; - }); - - Blender.register("screen", function(rgbaLayer, rgbaParent) { - return { - r: 255 - (((255 - rgbaLayer.r) * (255 - rgbaParent.r)) / 255), - g: 255 - (((255 - rgbaLayer.g) * (255 - rgbaParent.g)) / 255), - b: 255 - (((255 - rgbaLayer.b) * (255 - rgbaParent.b)) / 255) - }; - }); - - Blender.register("overlay", function(rgbaLayer, rgbaParent) { - var result; - result = {}; - result.r = rgbaParent.r > 128 ? 255 - 2 * (255 - rgbaLayer.r) * (255 - rgbaParent.r) / 255 : (rgbaParent.r * rgbaLayer.r * 2) / 255; - result.g = rgbaParent.g > 128 ? 255 - 2 * (255 - rgbaLayer.g) * (255 - rgbaParent.g) / 255 : (rgbaParent.g * rgbaLayer.g * 2) / 255; - result.b = rgbaParent.b > 128 ? 255 - 2 * (255 - rgbaLayer.b) * (255 - rgbaParent.b) / 255 : (rgbaParent.b * rgbaLayer.b * 2) / 255; - return result; - }); - - Blender.register("difference", function(rgbaLayer, rgbaParent) { - return { - r: rgbaLayer.r - rgbaParent.r, - g: rgbaLayer.g - rgbaParent.g, - b: rgbaLayer.b - rgbaParent.b - }; - }); - - Blender.register("addition", function(rgbaLayer, rgbaParent) { - return { - r: rgbaParent.r + rgbaLayer.r, - g: rgbaParent.g + rgbaLayer.g, - b: rgbaParent.b + rgbaLayer.b - }; - }); - - Blender.register("exclusion", function(rgbaLayer, rgbaParent) { - return { - r: 128 - 2 * (rgbaParent.r - 128) * (rgbaLayer.r - 128) / 255, - g: 128 - 2 * (rgbaParent.g - 128) * (rgbaLayer.g - 128) / 255, - b: 128 - 2 * (rgbaParent.b - 128) * (rgbaLayer.b - 128) / 255 - }; - }); - - Blender.register("softLight", function(rgbaLayer, rgbaParent) { - var result; - result = {}; - result.r = rgbaParent.r > 128 ? 255 - ((255 - rgbaParent.r) * (255 - (rgbaLayer.r - 128))) / 255 : (rgbaParent.r * (rgbaLayer.r + 128)) / 255; - result.g = rgbaParent.g > 128 ? 255 - ((255 - rgbaParent.g) * (255 - (rgbaLayer.g - 128))) / 255 : (rgbaParent.g * (rgbaLayer.g + 128)) / 255; - result.b = rgbaParent.b > 128 ? 255 - ((255 - rgbaParent.b) * (255 - (rgbaLayer.b - 128))) / 255 : (rgbaParent.b * (rgbaLayer.b + 128)) / 255; - return result; - }); - - Blender.register("lighten", function(rgbaLayer, rgbaParent) { - return { - r: rgbaParent.r > rgbaLayer.r ? rgbaParent.r : rgbaLayer.r, - g: rgbaParent.g > rgbaLayer.g ? rgbaParent.g : rgbaLayer.g, - b: rgbaParent.b > rgbaLayer.b ? rgbaParent.b : rgbaLayer.b - }; - }); - - Blender.register("darken", function(rgbaLayer, rgbaParent) { - return { - r: rgbaParent.r > rgbaLayer.r ? rgbaLayer.r : rgbaParent.r, - g: rgbaParent.g > rgbaLayer.g ? rgbaLayer.g : rgbaParent.g, - b: rgbaParent.b > rgbaLayer.b ? rgbaLayer.b : rgbaParent.b - }; - }); - - Filter.register("fillColor", function() { - var color; - if (arguments.length === 1) { - color = Convert.hexToRGB(arguments[0]); - } else { - color = { - r: arguments[0], - g: arguments[1], - b: arguments[2] - }; - } - return this.process("fillColor", function(rgba) { - rgba.r = color.r; - rgba.g = color.g; - rgba.b = color.b; - rgba.a = 255; - return rgba; - }); - }); - - Filter.register("brightness", function(adjust) { - adjust = Math.floor(255 * (adjust / 100)); - return this.process("brightness", function(rgba) { - rgba.r += adjust; - rgba.g += adjust; - rgba.b += adjust; - return rgba; - }); - }); - - Filter.register("saturation", function(adjust) { - adjust *= -0.01; - return this.process("saturation", function(rgba) { - var max; - max = Math.max(rgba.r, rgba.g, rgba.b); - if (rgba.r !== max) { - rgba.r += (max - rgba.r) * adjust; - } - if (rgba.g !== max) { - rgba.g += (max - rgba.g) * adjust; - } - if (rgba.b !== max) { - rgba.b += (max - rgba.b) * adjust; - } - return rgba; - }); - }); - - Filter.register("vibrance", function(adjust) { - adjust *= -1; - return this.process("vibrance", function(rgba) { - var amt, avg, max; - max = Math.max(rgba.r, rgba.g, rgba.b); - avg = (rgba.r + rgba.g + rgba.b) / 3; - amt = ((Math.abs(max - avg) * 2 / 255) * adjust) / 100; - if (rgba.r !== max) { - rgba.r += (max - rgba.r) * amt; - } - if (rgba.g !== max) { - rgba.g += (max - rgba.g) * amt; - } - if (rgba.b !== max) { - rgba.b += (max - rgba.b) * amt; - } - return rgba; - }); - }); - - Filter.register("greyscale", function(adjust) { - return this.process("greyscale", function(rgba) { - var avg; - avg = Calculate.luminance(rgba); - rgba.r = avg; - rgba.g = avg; - rgba.b = avg; - return rgba; - }); - }); - - Filter.register("contrast", function(adjust) { - adjust = Math.pow((adjust + 100) / 100, 2); - return this.process("contrast", function(rgba) { - rgba.r /= 255; - rgba.r -= 0.5; - rgba.r *= adjust; - rgba.r += 0.5; - rgba.r *= 255; - rgba.g /= 255; - rgba.g -= 0.5; - rgba.g *= adjust; - rgba.g += 0.5; - rgba.g *= 255; - rgba.b /= 255; - rgba.b -= 0.5; - rgba.b *= adjust; - rgba.b += 0.5; - rgba.b *= 255; - return rgba; - }); - }); - - Filter.register("hue", function(adjust) { - return this.process("hue", function(rgba) { - var h, hsv, rgb; - hsv = Convert.rgbToHSV(rgba.r, rgba.g, rgba.b); - h = hsv.h * 100; - h += Math.abs(adjust); - h = h % 100; - h /= 100; - hsv.h = h; - rgb = Convert.hsvToRGB(hsv.h, hsv.s, hsv.v); - rgb.a = rgba.a; - return rgb; - }); - }); - - Filter.register("colorize", function() { - var level, rgb; - if (arguments.length === 2) { - rgb = Convert.hexToRGB(arguments[0]); - level = arguments[1]; - } else if (arguments.length === 4) { - rgb = { - r: arguments[0], - g: arguments[1], - b: arguments[2] - }; - level = arguments[3]; - } - return this.process("colorize", function(rgba) { - rgba.r -= (rgba.r - rgb.r) * (level / 100); - rgba.g -= (rgba.g - rgb.g) * (level / 100); - rgba.b -= (rgba.b - rgb.b) * (level / 100); - return rgba; - }); - }); - - Filter.register("invert", function() { - return this.process("invert", function(rgba) { - rgba.r = 255 - rgba.r; - rgba.g = 255 - rgba.g; - rgba.b = 255 - rgba.b; - return rgba; - }); - }); - - Filter.register("sepia", function(adjust) { - if (adjust == null) { - adjust = 100; - } - adjust /= 100; - return this.process("sepia", function(rgba) { - rgba.r = Math.min(255, (rgba.r * (1 - (0.607 * adjust))) + (rgba.g * (0.769 * adjust)) + (rgba.b * (0.189 * adjust))); - rgba.g = Math.min(255, (rgba.r * (0.349 * adjust)) + (rgba.g * (1 - (0.314 * adjust))) + (rgba.b * (0.168 * adjust))); - rgba.b = Math.min(255, (rgba.r * (0.272 * adjust)) + (rgba.g * (0.534 * adjust)) + (rgba.b * (1 - (0.869 * adjust)))); - return rgba; - }); - }); - - Filter.register("gamma", function(adjust) { - return this.process("gamma", function(rgba) { - rgba.r = Math.pow(rgba.r / 255, adjust) * 255; - rgba.g = Math.pow(rgba.g / 255, adjust) * 255; - rgba.b = Math.pow(rgba.b / 255, adjust) * 255; - return rgba; - }); - }); - - Filter.register("noise", function(adjust) { - adjust = Math.abs(adjust) * 2.55; - return this.process("noise", function(rgba) { - var rand; - rand = Calculate.randomRange(adjust * -1, adjust); - rgba.r += rand; - rgba.g += rand; - rgba.b += rand; - return rgba; - }); - }); - - Filter.register("clip", function(adjust) { - adjust = Math.abs(adjust) * 2.55; - return this.process("clip", function(rgba) { - if (rgba.r > 255 - adjust) { - rgba.r = 255; - } else if (rgba.r < adjust) { - rgba.r = 0; - } - if (rgba.g > 255 - adjust) { - rgba.g = 255; - } else if (rgba.g < adjust) { - rgba.g = 0; - } - if (rgba.b > 255 - adjust) { - rgba.b = 255; - } else if (rgba.b < adjust) { - rgba.b = 0; - } - return rgba; - }); - }); - - Filter.register("channels", function(options) { - var chan, value; - if (typeof options !== "object") { - return this; - } - for (chan in options) { - if (!__hasProp.call(options, chan)) continue; - value = options[chan]; - if (value === 0) { - delete options[chan]; - continue; - } - options[chan] /= 100; - } - if (options.length === 0) { - return this; - } - return this.process("channels", function(rgba) { - if (options.red != null) { - if (options.red > 0) { - rgba.r += (255 - rgba.r) * options.red; - } else { - rgba.r -= rgba.r * Math.abs(options.red); - } - } - if (options.green != null) { - if (options.green > 0) { - rgba.g += (255 - rgba.g) * options.green; - } else { - rgba.g -= rgba.g * Math.abs(options.green); - } - } - if (options.blue != null) { - if (options.blue > 0) { - rgba.b += (255 - rgba.b) * options.blue; - } else { - rgba.b -= rgba.b * Math.abs(options.blue); - } - } - return rgba; - }); - }); - - Filter.register("curves", function() { - var bezier, chans, cps, ctrl1, ctrl2, end, i, start, _i, _j, _ref, _ref1; - chans = arguments[0], cps = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - if (typeof chans === "string") { - chans = chans.split(""); - } - if (chans[0] === "v") { - chans = ['r', 'g', 'b']; - } - if (cps.length < 3 || cps.length > 4) { - throw "Invalid number of arguments to curves filter"; - } - start = cps[0]; - ctrl1 = cps[1]; - ctrl2 = cps.length === 4 ? cps[2] : cps[1]; - end = cps[cps.length - 1]; - bezier = Calculate.bezier(start, ctrl1, ctrl2, end, 0, 255); - if (start[0] > 0) { - for (i = _i = 0, _ref = start[0]; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - bezier[i] = start[1]; - } - } - if (end[0] < 255) { - for (i = _j = _ref1 = end[0]; _ref1 <= 255 ? _j <= 255 : _j >= 255; i = _ref1 <= 255 ? ++_j : --_j) { - bezier[i] = end[1]; - } - } - return this.process("curves", function(rgba) { - var _k, _ref2; - for (i = _k = 0, _ref2 = chans.length; 0 <= _ref2 ? _k < _ref2 : _k > _ref2; i = 0 <= _ref2 ? ++_k : --_k) { - rgba[chans[i]] = bezier[rgba[chans[i]]]; - } - return rgba; - }); - }); - - Filter.register("exposure", function(adjust) { - var ctrl1, ctrl2, p; - p = Math.abs(adjust) / 100; - ctrl1 = [0, 255 * p]; - ctrl2 = [255 - (255 * p), 255]; - if (adjust < 0) { - ctrl1 = ctrl1.reverse(); - ctrl2 = ctrl2.reverse(); - } - return this.curves('rgb', [0, 0], ctrl1, ctrl2, [255, 255]); - }); - - Caman.Plugin.register("crop", function(width, height, x, y) { - var canvas, ctx; - if (x == null) { - x = 0; - } - if (y == null) { - y = 0; - } - if (typeof exports !== "undefined" && exports !== null) { - canvas = new Canvas(width, height); - } else { - canvas = document.createElement('canvas'); - Util.copyAttributes(this.canvas, canvas); - canvas.width = width; - canvas.height = height; - } - ctx = canvas.getContext('2d'); - ctx.drawImage(this.canvas, x, y, width, height, 0, 0, width, height); - this.cropCoordinates = { - x: x, - y: y - }; - this.cropped = true; - return this.replaceCanvas(canvas); - }); - - Caman.Plugin.register("resize", function(newDims) { - var canvas, ctx; - if (newDims == null) { - newDims = null; - } - if (newDims === null || ((newDims.width == null) && (newDims.height == null))) { - Log.error("Invalid or missing dimensions given for resize"); - return; - } - if (newDims.width == null) { - newDims.width = this.canvas.width * newDims.height / this.canvas.height; - } else if (newDims.height == null) { - newDims.height = this.canvas.height * newDims.width / this.canvas.width; - } - if (typeof exports !== "undefined" && exports !== null) { - canvas = new Canvas(newDims.width, newDims.height); - } else { - canvas = document.createElement('canvas'); - Util.copyAttributes(this.canvas, canvas); - canvas.width = newDims.width; - canvas.height = newDims.height; - } - ctx = canvas.getContext('2d'); - ctx.drawImage(this.canvas, 0, 0, this.canvas.width, this.canvas.height, 0, 0, newDims.width, newDims.height); - this.resized = true; - return this.replaceCanvas(canvas); - }); - - Caman.Filter.register("crop", function() { - return this.processPlugin("crop", Array.prototype.slice.call(arguments, 0)); - }); - - Caman.Filter.register("resize", function() { - return this.processPlugin("resize", Array.prototype.slice.call(arguments, 0)); - }); - - /* - IDMC plugins - */ - - - Caman.Filter.register("idmc_reset_original_pixeldata", function() { - return this.processPlugin("idmc_reset_original_pixeldata", null); - }); - - Caman.Plugin.register("idmc_reset_original_pixeldata", function() { - var i, pixel, _i, _len, _ref; - Log.debug("idmc_reset_original_pixeldata"); - this.originalPixelData = Util.dataArray(this.pixelData.length); - _ref = this.pixelData; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - pixel = _ref[i]; - this.originalPixelData[i] = pixel; - } - return this; - }); - - Caman.Filter.register("idmc_set_min_max_pixel_values", function(min_pixel_value, max_pixel_value) { - return this.processPlugin("idmc_set_min_max_pixel_values", [min_pixel_value, max_pixel_value]); - }); - - Caman.Plugin.register("idmc_set_min_max_pixel_values", function(min_pixel_value, max_pixel_value) { - var a, b, b_colormap, g, g_colormap, height, i, idx, index, org_pixels, pixels, r, r_colormap, width, x, y, _i, _j, _k, - _this = this, tmp; - tmp = []; - for (i = _i = 0; _i < 256; i = ++_i) { - tmp.push(0); - } - - org_pixels = this.originalPixelData; - pixels = this.pixelData; - width = this.dimensions.width; - height = this.dimensions.height; - - console.debug('idmc_set_min_max_pixel_values: width: ' + width); - console.debug('idmc_set_min_max_pixel_values: height: ' + height); - if (this.idmc_set_min_max_pixel_values_r_colormap == null) { - this.idmc_set_min_max_pixel_values_r_colormap = (function() { - var _i, _results; - _results = []; - for (i = _i = 0; _i < 256; i = ++_i) { - _results.push(i); - } - return _results; - })(); - } - if (this.idmc_set_min_max_pixel_values_g_colormap == null) { - this.idmc_set_min_max_pixel_values_g_colormap = (function() { - var _i, _results; - _results = []; - for (i = _i = 0; _i < 256; i = ++_i) { - _results.push(i); - } - return _results; - })(); - } - if (this.idmc_set_min_max_pixel_values_b_colormap == null) { - this.idmc_set_min_max_pixel_values_b_colormap = (function() { - var _i, _results; - _results = []; - for (i = _i = 0; _i < 256; i = ++_i) { - _results.push(i); - } - return _results; - })(); - } - r_colormap = this.idmc_set_min_max_pixel_values_r_colormap; - g_colormap = this.idmc_set_min_max_pixel_values_g_colormap; - b_colormap = this.idmc_set_min_max_pixel_values_b_colormap; - - - idx = function(x, y) { - return (y * width + x) * 4; - }; - for (i = _i = 0; _i < 256; i = ++_i) { - index = Math.round((256 * (i - min_pixel_value)) / (max_pixel_value - min_pixel_value)); - index = index < 0 ? 0 : i > 255 ? 255 : index; - r_colormap[i] = i < min_pixel_value ? 0 : i > max_pixel_value ? 255 : index; - g_colormap[i] = i < min_pixel_value ? 0 : i > max_pixel_value ? 255 : index; - b_colormap[i] = i < min_pixel_value ? 0 : i > max_pixel_value ? 255 : index; - } - for (y = _j = 0; 0 <= height ? _j < height : _j > height; y = 0 <= height ? ++_j : --_j) { - for (x = _k = 0; 0 <= width ? _k < width : _k > width; x = 0 <= width ? ++_k : --_k) { - r = org_pixels[idx(x, y)]; - g = org_pixels[idx(x, y) + 1]; - b = org_pixels[idx(x, y) + 2]; - a = org_pixels[idx(x, y) + 3]; - pixels[idx(x, y)] = r_colormap[r]; - pixels[idx(x, y) + 1] = g_colormap[g]; - pixels[idx(x, y) + 2] = b_colormap[b]; - pixels[idx(x, y) + 3] = 255; - //tmp[r] += 1; - } - } - - for (var i=0; i < height * width; i = i + 4) { - tmp[org_pixels[i]] += 1; - tmp[org_pixels[i+1]] += 1; - tmp[org_pixels[i+2]] += 1; - } - - /* - alert('caman heigt: ' + height + - '\ncaman width: ' + width); - */ - //alert(tmp[30]); - return this; - }); - - Caman.Filter.register("idmc_test", function() { - return this.processPlugin("idmc_test", []); - }); - - Caman.Plugin.register("idmc_test", function() { - return this.process("idmc_test", function(rgba) { - Log.debug("IDMC test func"); - return rgba; - }); - }); - - this; - -}).call(this); diff --git a/mig/images/lib/CamanJS-4.1.1/dist/caman.js b/mig/images/lib/CamanJS-4.1.1/dist/caman.js deleted file mode 100644 index b9a578865..000000000 --- a/mig/images/lib/CamanJS-4.1.1/dist/caman.js +++ /dev/null @@ -1,2321 +0,0 @@ -// Generated by CoffeeScript 1.6.3 -(function() { - var $, Analyze, Blender, Calculate, Caman, CamanParser, Canvas, Convert, Event, Fiber, Filter, IO, Image, Layer, Log, Logger, PixelInfo, Plugin, Renderer, Root, Store, Util, fs, slice, - __hasProp = {}.hasOwnProperty, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, - __slice = [].slice, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; - - slice = Array.prototype.slice; - - $ = function(sel, root) { - if (root == null) { - root = document; - } - if (typeof sel === "object" || (typeof exports !== "undefined" && exports !== null)) { - return sel; - } - return root.querySelector(sel); - }; - - Util = (function() { - function Util() {} - - Util.uniqid = (function() { - var id; - id = 0; - return { - get: function() { - return id++; - } - }; - })(); - - Util.extend = function(obj) { - var copy, dest, prop, src, _i, _len; - dest = obj; - src = slice.call(arguments, 1); - for (_i = 0, _len = src.length; _i < _len; _i++) { - copy = src[_i]; - for (prop in copy) { - if (!__hasProp.call(copy, prop)) continue; - dest[prop] = copy[prop]; - } - } - return dest; - }; - - Util.clampRGB = function(val) { - if (val < 0) { - return 0; - } - if (val > 255) { - return 255; - } - return val; - }; - - Util.copyAttributes = function(from, to, opts) { - var attr, _i, _len, _ref, _ref1, _results; - if (opts == null) { - opts = {}; - } - _ref = from.attributes; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - attr = _ref[_i]; - if ((opts.except != null) && (_ref1 = attr.nodeName, __indexOf.call(opts.except, _ref1) >= 0)) { - continue; - } - _results.push(to.setAttribute(attr.nodeName, attr.nodeValue)); - } - return _results; - }; - - Util.dataArray = function(length) { - if (length == null) { - length = 0; - } - if (Caman.NodeJS || (window.Uint8Array != null)) { - return new Uint8Array(length); - } - return new Array(length); - }; - - return Util; - - })(); - - if (typeof exports !== "undefined" && exports !== null) { - Root = exports; - Canvas = require('canvas'); - Image = Canvas.Image; - Fiber = require('fibers'); - fs = require('fs'); - } else { - Root = window; - } - - Root.Caman = Caman = (function() { - Caman.version = { - release: "4.1.1", - date: "4/8/2013" - }; - - Caman.DEBUG = false; - - Caman.NodeJS = typeof exports !== "undefined" && exports !== null; - - Caman.autoload = !Caman.NodeJS; - - Caman.allowRevert = true; - - Caman.crossOrigin = "anonymous"; - - Caman.toString = function() { - return "Version " + Caman.version.release + ", Released " + Caman.version.date; - }; - - Caman.remoteProxy = ""; - - Caman.proxyParam = "camanProxyUrl"; - - Caman.getAttrId = function(canvas) { - if (Caman.NodeJS) { - return true; - } - if (typeof canvas === "string") { - canvas = $(canvas); - } - if (!((canvas != null) && (canvas.getAttribute != null))) { - return null; - } - return canvas.getAttribute('data-caman-id'); - }; - - function Caman() { - var args, callback, id, - _this = this; - if (arguments.length === 0) { - throw "Invalid arguments"; - } - if (this instanceof Caman) { - this.finishInit = this.finishInit.bind(this); - this.imageLoaded = this.imageLoaded.bind(this); - args = arguments[0]; - if (!Caman.NodeJS) { - id = parseInt(Caman.getAttrId(args[0]), 10); - callback = typeof args[1] === "function" ? args[1] : typeof args[2] === "function" ? args[2] : function() {}; - if (!isNaN(id) && Store.has(id)) { - return Store.execute(id, callback); - } - } - this.id = Util.uniqid.get(); - this.initializedPixelData = this.originalPixelData = null; - this.cropCoordinates = { - x: 0, - y: 0 - }; - this.cropped = false; - this.resized = false; - this.pixelStack = []; - this.layerStack = []; - this.canvasQueue = []; - this.currentLayer = null; - this.scaled = false; - this.analyze = new Analyze(this); - this.renderer = new Renderer(this); - this.domIsLoaded(function() { - _this.parseArguments(args); - return _this.setup(); - }); - return this; - } else { - return new Caman(arguments); - } - } - - Caman.prototype.domIsLoaded = function(cb) { - var listener, - _this = this; - if (Caman.NodeJS) { - return setTimeout(function() { - return cb.call(_this); - }, 0); - } else { - if (document.readyState === "complete") { - Log.debug("DOM initialized"); - return setTimeout(function() { - return cb.call(_this); - }, 0); - } else { - listener = function() { - if (document.readyState === "complete") { - Log.debug("DOM initialized"); - return cb.call(_this); - } - }; - return document.addEventListener("readystatechange", listener, false); - } - } - }; - - Caman.prototype.parseArguments = function(args) { - var key, val, _ref, _results; - if (args.length === 0) { - throw "Invalid arguments given"; - } - this.initObj = null; - this.initType = null; - this.imageUrl = null; - this.callback = function() {}; - this.setInitObject(args[0]); - if (args.length === 1) { - return; - } - switch (typeof args[1]) { - case "string": - this.imageUrl = args[1]; - break; - case "function": - this.callback = args[1]; - } - if (args.length === 2) { - return; - } - this.callback = args[2]; - if (args.length === 4) { - _ref = args[4]; - _results = []; - for (key in _ref) { - if (!__hasProp.call(_ref, key)) continue; - val = _ref[key]; - _results.push(this.options[key] = val); - } - return _results; - } - }; - - Caman.prototype.setInitObject = function(obj) { - if (Caman.NodeJS) { - this.initObj = obj; - this.initType = 'node'; - return; - } - if (typeof obj === "object") { - this.initObj = obj; - } else { - this.initObj = $(obj); - } - if (this.initObj == null) { - throw "Could not find image or canvas for initialization."; - } - return this.initType = this.initObj.nodeName.toLowerCase(); - }; - - Caman.prototype.setup = function() { - switch (this.initType) { - case "node": - return this.initNode(); - case "img": - return this.initImage(); - case "canvas": - return this.initCanvas(); - } - }; - - Caman.prototype.initNode = function() { - var _this = this; - Log.debug("Initializing for NodeJS"); - this.image = new Image(); - this.image.onload = function() { - Log.debug("Image loaded. Width = " + (_this.imageWidth()) + ", Height = " + (_this.imageHeight())); - _this.canvas = new Canvas(_this.imageWidth(), _this.imageHeight()); - return _this.finishInit(); - }; - this.image.onerror = function(err) { - throw err; - }; - return this.image.src = this.initObj; - }; - - Caman.prototype.initImage = function() { - this.image = this.initObj; - this.canvas = document.createElement('canvas'); - this.context = this.canvas.getContext('2d'); - Util.copyAttributes(this.image, this.canvas, { - except: ['src'] - }); - this.image.parentNode.replaceChild(this.canvas, this.image); - this.imageAdjustments(); - return this.waitForImageLoaded(); - }; - - Caman.prototype.initCanvas = function() { - this.canvas = this.initObj; - this.context = this.canvas.getContext('2d'); - if (this.imageUrl != null) { - this.image = document.createElement('img'); - this.image.src = this.imageUrl; - this.imageAdjustments(); - return this.waitForImageLoaded(); - } else { - return this.finishInit(); - } - }; - - Caman.prototype.imageAdjustments = function() { - if (this.needsHiDPISwap()) { - Log.debug(this.image.src, "->", this.hiDPIReplacement()); - this.swapped = true; - this.image.src = this.hiDPIReplacement(); - } - if (IO.isRemote(this.image)) { - this.image.src = IO.proxyUrl(this.image.src); - return Log.debug("Remote image detected, using URL = " + this.image.src); - } - }; - - Caman.prototype.waitForImageLoaded = function() { - if (this.isImageLoaded()) { - return this.imageLoaded(); - } else { - return this.image.onload = this.imageLoaded; - } - }; - - Caman.prototype.isImageLoaded = function() { - if (!this.image.complete) { - return false; - } - if ((this.image.naturalWidth != null) && this.image.naturalWidth === 0) { - return false; - } - return true; - }; - - Caman.prototype.imageWidth = function() { - return this.image.width || this.image.naturalWidth; - }; - - Caman.prototype.imageHeight = function() { - return this.image.height || this.image.naturalHeight; - }; - - Caman.prototype.imageLoaded = function() { - Log.debug("Image loaded. Width = " + (this.imageWidth()) + ", Height = " + (this.imageHeight())); - if (this.swapped) { - this.canvas.width = this.imageWidth() / this.hiDPIRatio(); - this.canvas.height = this.imageHeight() / this.hiDPIRatio(); - } else { - this.canvas.width = this.imageWidth(); - this.canvas.height = this.imageHeight(); - } - return this.finishInit(); - }; - - Caman.prototype.finishInit = function() { - var i, pixel, _i, _len, _ref; - if (this.context == null) { - this.context = this.canvas.getContext('2d'); - } - this.originalWidth = this.preScaledWidth = this.width = this.canvas.width; - this.originalHeight = this.preScaledHeight = this.height = this.canvas.height; - this.hiDPIAdjustments(); - if (!this.hasId()) { - this.assignId(); - } - if (this.image != null) { - this.context.drawImage(this.image, 0, 0, this.imageWidth(), this.imageHeight(), 0, 0, this.preScaledWidth, this.preScaledHeight); - } - this.reloadCanvasData(); - if (Caman.allowRevert) { - this.initializedPixelData = Util.dataArray(this.pixelData.length); - this.originalPixelData = Util.dataArray(this.pixelData.length); - _ref = this.pixelData; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - pixel = _ref[i]; - this.initializedPixelData[i] = pixel; - this.originalPixelData[i] = pixel; - } - } - this.dimensions = { - width: this.canvas.width, - height: this.canvas.height - }; - Store.put(this.id, this); - this.callback.call(this, this); - return this.callback = function() {}; - }; - - Caman.prototype.reloadCanvasData = function() { - this.imageData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - return this.pixelData = this.imageData.data; - }; - - Caman.prototype.resetOriginalPixelData = function() { - var pixel, _i, _len, _ref, _results; - if (!Caman.allowRevert) { - throw "Revert disabled"; - } - this.originalPixelData = Util.dataArray(this.pixelData.length); - _ref = this.pixelData; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - pixel = _ref[_i]; - _results.push(this.originalPixelData.push(pixel)); - } - return _results; - }; - - Caman.prototype.hasId = function() { - return Caman.getAttrId(this.canvas) != null; - }; - - Caman.prototype.assignId = function() { - if (Caman.NodeJS || this.canvas.getAttribute('data-caman-id')) { - return; - } - return this.canvas.setAttribute('data-caman-id', this.id); - }; - - Caman.prototype.hiDPIDisabled = function() { - return this.canvas.getAttribute('data-caman-hidpi-disabled') !== null; - }; - - Caman.prototype.hiDPIAdjustments = function() { - var ratio; - if (Caman.NodeJS || this.hiDPIDisabled()) { - return; - } - ratio = this.hiDPIRatio(); - if (ratio !== 1) { - Log.debug("HiDPI ratio = " + ratio); - this.scaled = true; - this.preScaledWidth = this.canvas.width; - this.preScaledHeight = this.canvas.height; - this.canvas.width = this.preScaledWidth * ratio; - this.canvas.height = this.preScaledHeight * ratio; - this.canvas.style.width = "" + this.preScaledWidth + "px"; - this.canvas.style.height = "" + this.preScaledHeight + "px"; - this.context.scale(ratio, ratio); - this.width = this.originalWidth = this.canvas.width; - return this.height = this.originalHeight = this.canvas.height; - } - }; - - Caman.prototype.hiDPIRatio = function() { - var backingStoreRatio, devicePixelRatio; - devicePixelRatio = window.devicePixelRatio || 1; - backingStoreRatio = this.context.webkitBackingStorePixelRatio || this.context.mozBackingStorePixelRatio || this.context.msBackingStorePixelRatio || this.context.oBackingStorePixelRatio || this.context.backingStorePixelRatio || 1; - return devicePixelRatio / backingStoreRatio; - }; - - Caman.prototype.hiDPICapable = function() { - return (window.devicePixelRatio != null) && window.devicePixelRatio !== 1; - }; - - Caman.prototype.needsHiDPISwap = function() { - if (this.hiDPIDisabled() || !this.hiDPICapable()) { - return false; - } - return this.hiDPIReplacement() !== null; - }; - - Caman.prototype.hiDPIReplacement = function() { - if (this.image == null) { - return null; - } - return this.image.getAttribute('data-caman-hidpi'); - }; - - Caman.prototype.replaceCanvas = function(newCanvas) { - var oldCanvas; - oldCanvas = this.canvas; - this.canvas = newCanvas; - this.context = this.canvas.getContext('2d'); - oldCanvas.parentNode.replaceChild(this.canvas, oldCanvas); - this.width = this.canvas.width; - this.height = this.canvas.height; - this.reloadCanvasData(); - return this.dimensions = { - width: this.canvas.width, - height: this.canvas.height - }; - }; - - Caman.prototype.render = function(callback) { - var _this = this; - if (callback == null) { - callback = function() {}; - } - Event.trigger(this, "renderStart"); - return this.renderer.execute(function() { - _this.context.putImageData(_this.imageData, 0, 0); - return callback.call(_this); - }); - }; - - Caman.prototype.revert = function() { - var i, pixel, _i, _len, _ref; - if (!Caman.allowRevert) { - throw "Revert disabled"; - } - _ref = this.originalVisiblePixels(); - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - pixel = _ref[i]; - this.pixelData[i] = pixel; - } - return this.context.putImageData(this.imageData, 0, 0); - }; - - Caman.prototype.reset = function() { - var canvas, ctx, i, imageData, pixel, pixelData, _i, _len, _ref; - canvas = document.createElement('canvas'); - Util.copyAttributes(this.canvas, canvas); - canvas.width = this.originalWidth; - canvas.height = this.originalHeight; - ctx = canvas.getContext('2d'); - imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); - pixelData = imageData.data; - _ref = this.initializedPixelData; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - pixel = _ref[i]; - pixelData[i] = pixel; - } - ctx.putImageData(imageData, 0, 0); - this.cropCoordinates = { - x: 0, - y: 0 - }; - this.resized = false; - return this.replaceCanvas(canvas); - }; - - Caman.prototype.originalVisiblePixels = function() { - var canvas, coord, ctx, endX, endY, i, imageData, pixel, pixelData, pixels, scaledCanvas, startX, startY, width, _i, _j, _len, _ref, _ref1, _ref2, _ref3; - if (!Caman.allowRevert) { - throw "Revert disabled"; - } - pixels = []; - startX = this.cropCoordinates.x; - endX = startX + this.width; - startY = this.cropCoordinates.y; - endY = startY + this.height; - if (this.resized) { - canvas = document.createElement('canvas'); - canvas.width = this.originalWidth; - canvas.height = this.originalHeight; - ctx = canvas.getContext('2d'); - imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); - pixelData = imageData.data; - _ref = this.originalPixelData; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - pixel = _ref[i]; - pixelData[i] = pixel; - } - ctx.putImageData(imageData, 0, 0); - scaledCanvas = document.createElement('canvas'); - scaledCanvas.width = this.width; - scaledCanvas.height = this.height; - ctx = scaledCanvas.getContext('2d'); - ctx.drawImage(canvas, 0, 0, this.originalWidth, this.originalHeight, 0, 0, this.width, this.height); - pixelData = ctx.getImageData(0, 0, this.width, this.height).data; - width = this.width; - } else { - pixelData = this.originalPixelData; - width = this.originalWidth; - } - for (i = _j = 0, _ref1 = pixelData.length; _j < _ref1; i = _j += 4) { - coord = PixelInfo.locationToCoordinates(i, width); - if (((startX <= (_ref2 = coord.x) && _ref2 < endX)) && ((startY <= (_ref3 = coord.y) && _ref3 < endY))) { - pixels.push(pixelData[i], pixelData[i + 1], pixelData[i + 2], pixelData[i + 3]); - } - } - return pixels; - }; - - Caman.prototype.process = function(name, processFn) { - this.renderer.add({ - type: Filter.Type.Single, - name: name, - processFn: processFn - }); - return this; - }; - - Caman.prototype.processKernel = function(name, adjust, divisor, bias) { - var i, _i, _ref; - if (!divisor) { - divisor = 0; - for (i = _i = 0, _ref = adjust.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - divisor += adjust[i]; - } - } - this.renderer.add({ - type: Filter.Type.Kernel, - name: name, - adjust: adjust, - divisor: divisor, - bias: bias || 0 - }); - return this; - }; - - Caman.prototype.processPlugin = function(plugin, args) { - this.renderer.add({ - type: Filter.Type.Plugin, - plugin: plugin, - args: args - }); - return this; - }; - - Caman.prototype.newLayer = function(callback) { - var layer; - layer = new Layer(this); - this.canvasQueue.push(layer); - this.renderer.add({ - type: Filter.Type.LayerDequeue - }); - callback.call(layer); - this.renderer.add({ - type: Filter.Type.LayerFinished - }); - return this; - }; - - Caman.prototype.executeLayer = function(layer) { - return this.pushContext(layer); - }; - - Caman.prototype.pushContext = function(layer) { - this.layerStack.push(this.currentLayer); - this.pixelStack.push(this.pixelData); - this.currentLayer = layer; - return this.pixelData = layer.pixelData; - }; - - Caman.prototype.popContext = function() { - this.pixelData = this.pixelStack.pop(); - return this.currentLayer = this.layerStack.pop(); - }; - - Caman.prototype.applyCurrentLayer = function() { - return this.currentLayer.applyToParent(); - }; - - return Caman; - - })(); - - Analyze = (function() { - function Analyze(c) { - this.c = c; - } - - Analyze.prototype.calculateLevels = function() { - var i, levels, numPixels, _i, _j, _k, _ref; - levels = { - r: {}, - g: {}, - b: {} - }; - for (i = _i = 0; _i <= 255; i = ++_i) { - levels.r[i] = 0; - levels.g[i] = 0; - levels.b[i] = 0; - } - for (i = _j = 0, _ref = this.c.pixelData.length; _j < _ref; i = _j += 4) { - levels.r[this.c.pixelData[i]]++; - levels.g[this.c.pixelData[i + 1]]++; - levels.b[this.c.pixelData[i + 2]]++; - } - numPixels = this.c.pixelData.length / 4; - for (i = _k = 0; _k <= 255; i = ++_k) { - levels.r[i] /= numPixels; - levels.g[i] /= numPixels; - levels.b[i] /= numPixels; - } - return levels; - }; - - return Analyze; - - })(); - - Caman.DOMUpdated = function() { - var img, imgs, parser, _i, _len, _results; - imgs = document.querySelectorAll("img[data-caman]"); - if (!(imgs.length > 0)) { - return; - } - _results = []; - for (_i = 0, _len = imgs.length; _i < _len; _i++) { - img = imgs[_i]; - _results.push(parser = new CamanParser(img, function() { - this.parse(); - return this.execute(); - })); - } - return _results; - }; - - if (Caman.autoload) { - (function() { - if (document.readyState === "complete") { - return Caman.DOMUpdated(); - } else { - return document.addEventListener("DOMContentLoaded", Caman.DOMUpdated, false); - } - })(); - } - - CamanParser = (function() { - var INST_REGEX; - - INST_REGEX = "(\\w+)\\((.*?)\\)"; - - function CamanParser(ele, ready) { - this.dataStr = ele.getAttribute('data-caman'); - this.caman = Caman(ele, ready.bind(this)); - } - - CamanParser.prototype.parse = function() { - var args, e, filter, func, inst, instFunc, m, r, unparsedInstructions, _i, _len, _ref, _results; - this.ele = this.caman.canvas; - r = new RegExp(INST_REGEX, 'g'); - unparsedInstructions = this.dataStr.match(r); - if (!(unparsedInstructions.length > 0)) { - return; - } - r = new RegExp(INST_REGEX); - _results = []; - for (_i = 0, _len = unparsedInstructions.length; _i < _len; _i++) { - inst = unparsedInstructions[_i]; - _ref = inst.match(r), m = _ref[0], filter = _ref[1], args = _ref[2]; - instFunc = new Function("return function() { this." + filter + "(" + args + "); };"); - try { - func = instFunc(); - _results.push(func.call(this.caman)); - } catch (_error) { - e = _error; - _results.push(Log.debug(e)); - } - } - return _results; - }; - - CamanParser.prototype.execute = function() { - var ele; - ele = this.ele; - return this.caman.render(function() { - return ele.parentNode.replaceChild(this.toImage(), ele); - }); - }; - - return CamanParser; - - })(); - - Caman.Blender = Blender = (function() { - function Blender() {} - - Blender.blenders = {}; - - Blender.register = function(name, func) { - return this.blenders[name] = func; - }; - - Blender.execute = function(name, rgbaLayer, rgbaParent) { - return this.blenders[name](rgbaLayer, rgbaParent); - }; - - return Blender; - - })(); - - Caman.Calculate = Calculate = (function() { - function Calculate() {} - - Calculate.distance = function(x1, y1, x2, y2) { - return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); - }; - - Calculate.randomRange = function(min, max, getFloat) { - var rand; - if (getFloat == null) { - getFloat = false; - } - rand = min + (Math.random() * (max - min)); - if (getFloat) { - return rand.toFixed(getFloat); - } else { - return Math.round(rand); - } - }; - - Calculate.luminance = function(rgba) { - return (0.299 * rgba.r) + (0.587 * rgba.g) + (0.114 * rgba.b); - }; - - Calculate.bezier = function(start, ctrl1, ctrl2, end, lowBound, highBound) { - var Ax, Ay, Bx, By, Cx, Cy, bezier, curveX, curveY, i, j, leftCoord, rightCoord, t, x0, x1, x2, x3, y0, y1, y2, y3, _i, _j, _k, _ref, _ref1; - x0 = start[0]; - y0 = start[1]; - x1 = ctrl1[0]; - y1 = ctrl1[1]; - x2 = ctrl2[0]; - y2 = ctrl2[1]; - x3 = end[0]; - y3 = end[1]; - bezier = {}; - Cx = parseInt(3 * (x1 - x0), 10); - Bx = 3 * (x2 - x1) - Cx; - Ax = x3 - x0 - Cx - Bx; - Cy = 3 * (y1 - y0); - By = 3 * (y2 - y1) - Cy; - Ay = y3 - y0 - Cy - By; - for (i = _i = 0; _i < 1000; i = ++_i) { - t = i / 1000; - curveX = Math.round((Ax * Math.pow(t, 3)) + (Bx * Math.pow(t, 2)) + (Cx * t) + x0); - curveY = Math.round((Ay * Math.pow(t, 3)) + (By * Math.pow(t, 2)) + (Cy * t) + y0); - if (lowBound && curveY < lowBound) { - curveY = lowBound; - } else if (highBound && curveY > highBound) { - curveY = highBound; - } - bezier[curveX] = curveY; - } - if (bezier.length < end[0] + 1) { - for (i = _j = 0, _ref = end[0]; 0 <= _ref ? _j <= _ref : _j >= _ref; i = 0 <= _ref ? ++_j : --_j) { - if (bezier[i] == null) { - leftCoord = [i - 1, bezier[i - 1]]; - for (j = _k = i, _ref1 = end[0]; i <= _ref1 ? _k <= _ref1 : _k >= _ref1; j = i <= _ref1 ? ++_k : --_k) { - if (bezier[j] != null) { - rightCoord = [j, bezier[j]]; - break; - } - } - bezier[i] = leftCoord[1] + ((rightCoord[1] - leftCoord[1]) / (rightCoord[0] - leftCoord[0])) * (i - leftCoord[0]); - } - } - } - if (bezier[end[0]] == null) { - bezier[end[0]] = bezier[end[0] - 1]; - } - return bezier; - }; - - return Calculate; - - })(); - - Convert = (function() { - function Convert() {} - - Convert.hexToRGB = function(hex) { - var b, g, r; - if (hex.charAt(0) === "#") { - hex = hex.substr(1); - } - r = parseInt(hex.substr(0, 2), 16); - g = parseInt(hex.substr(2, 2), 16); - b = parseInt(hex.substr(4, 2), 16); - return { - r: r, - g: g, - b: b - }; - }; - - Convert.rgbToHSL = function(r, g, b) { - var d, h, l, max, min, s; - if (typeof r === "object") { - g = r.g; - b = r.b; - r = r.r; - } - r /= 255; - g /= 255; - b /= 255; - max = Math.max(r, g, b); - min = Math.min(r, g, b); - l = (max + min) / 2; - if (max === min) { - h = s = 0; - } else { - d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - h = (function() { - switch (max) { - case r: - return (g - b) / d + (g < b ? 6 : 0); - case g: - return (b - r) / d + 2; - case b: - return (r - g) / d + 4; - } - })(); - h /= 6; - } - return { - h: h, - s: s, - l: l - }; - }; - - Convert.hslToRGB = function(h, s, l) { - var b, g, p, q, r; - if (typeof h === "object") { - s = h.s; - l = h.l; - h = h.h; - } - if (s === 0) { - r = g = b = l; - } else { - q = l < 0.5 ? l * (1 + s) : l + s - l * s; - p = 2 * l - q; - r = this.hueToRGB(p, q, h + 1 / 3); - g = this.hueToRGB(p, q, h); - b = this.hueToRGB(p, q, h - 1 / 3); - } - return { - r: r * 255, - g: g * 255, - b: b * 255 - }; - }; - - Convert.hueToRGB = function(p, q, t) { - if (t < 0) { - t += 1; - } - if (t > 1) { - t -= 1; - } - if (t < 1 / 6) { - return p + (q - p) * 6 * t; - } - if (t < 1 / 2) { - return q; - } - if (t < 2 / 3) { - return p + (q - p) * (2 / 3 - t) * 6; - } - return p; - }; - - Convert.rgbToHSV = function(r, g, b) { - var d, h, max, min, s, v; - r /= 255; - g /= 255; - b /= 255; - max = Math.max(r, g, b); - min = Math.min(r, g, b); - v = max; - d = max - min; - s = max === 0 ? 0 : d / max; - if (max === min) { - h = 0; - } else { - h = (function() { - switch (max) { - case r: - return (g - b) / d + (g < b ? 6 : 0); - case g: - return (b - r) / d + 2; - case b: - return (r - g) / d + 4; - } - })(); - h /= 6; - } - return { - h: h, - s: s, - v: v - }; - }; - - Convert.hsvToRGB = function(h, s, v) { - var b, f, g, i, p, q, r, t; - i = Math.floor(h * 6); - f = h * 6 - i; - p = v * (1 - s); - q = v * (1 - f * s); - t = v * (1 - (1 - f) * s); - switch (i % 6) { - case 0: - r = v; - g = t; - b = p; - break; - case 1: - r = q; - g = v; - b = p; - break; - case 2: - r = p; - g = v; - b = t; - break; - case 3: - r = p; - g = q; - b = v; - break; - case 4: - r = t; - g = p; - b = v; - break; - case 5: - r = v; - g = p; - b = q; - } - return { - r: r * 255, - g: g * 255, - b: b * 255 - }; - }; - - Convert.rgbToXYZ = function(r, g, b) { - var x, y, z; - r /= 255; - g /= 255; - b /= 255; - if (r > 0.04045) { - r = Math.pow((r + 0.055) / 1.055, 2.4); - } else { - r /= 12.92; - } - if (g > 0.04045) { - g = Math.pow((g + 0.055) / 1.055, 2.4); - } else { - g /= 12.92; - } - if (b > 0.04045) { - b = Math.pow((b + 0.055) / 1.055, 2.4); - } else { - b /= 12.92; - } - x = r * 0.4124 + g * 0.3576 + b * 0.1805; - y = r * 0.2126 + g * 0.7152 + b * 0.0722; - z = r * 0.0193 + g * 0.1192 + b * 0.9505; - return { - x: x * 100, - y: y * 100, - z: z * 100 - }; - }; - - Convert.xyzToRGB = function(x, y, z) { - var b, g, r; - x /= 100; - y /= 100; - z /= 100; - r = (3.2406 * x) + (-1.5372 * y) + (-0.4986 * z); - g = (-0.9689 * x) + (1.8758 * y) + (0.0415 * z); - b = (0.0557 * x) + (-0.2040 * y) + (1.0570 * z); - if (r > 0.0031308) { - r = (1.055 * Math.pow(r, 0.4166666667)) - 0.055; - } else { - r *= 12.92; - } - if (g > 0.0031308) { - g = (1.055 * Math.pow(g, 0.4166666667)) - 0.055; - } else { - g *= 12.92; - } - if (b > 0.0031308) { - b = (1.055 * Math.pow(b, 0.4166666667)) - 0.055; - } else { - b *= 12.92; - } - return { - r: r * 255, - g: g * 255, - b: b * 255 - }; - }; - - Convert.xyzToLab = function(x, y, z) { - var a, b, l, whiteX, whiteY, whiteZ; - if (typeof x === "object") { - y = x.y; - z = x.z; - x = x.x; - } - whiteX = 95.047; - whiteY = 100.0; - whiteZ = 108.883; - x /= whiteX; - y /= whiteY; - z /= whiteZ; - if (x > 0.008856451679) { - x = Math.pow(x, 0.3333333333); - } else { - x = (7.787037037 * x) + 0.1379310345; - } - if (y > 0.008856451679) { - y = Math.pow(y, 0.3333333333); - } else { - y = (7.787037037 * y) + 0.1379310345; - } - if (z > 0.008856451679) { - z = Math.pow(z, 0.3333333333); - } else { - z = (7.787037037 * z) + 0.1379310345; - } - l = 116 * y - 16; - a = 500 * (x - y); - b = 200 * (y - z); - return { - l: l, - a: a, - b: b - }; - }; - - Convert.labToXYZ = function(l, a, b) { - var x, y, z; - if (typeof l === "object") { - a = l.a; - b = l.b; - l = l.l; - } - y = (l + 16) / 116; - x = y + (a / 500); - z = y - (b / 200); - if (x > 0.2068965517) { - x = x * x * x; - } else { - x = 0.1284185493 * (x - 0.1379310345); - } - if (y > 0.2068965517) { - y = y * y * y; - } else { - y = 0.1284185493 * (y - 0.1379310345); - } - if (z > 0.2068965517) { - z = z * z * z; - } else { - z = 0.1284185493 * (z - 0.1379310345); - } - return { - x: x * 95.047, - y: y * 100.0, - z: z * 108.883 - }; - }; - - Convert.rgbToLab = function(r, g, b) { - var xyz; - if (typeof r === "object") { - g = r.g; - b = r.b; - r = r.r; - } - xyz = this.rgbToXYZ(r, g, b); - return this.xyzToLab(xyz); - }; - - Convert.labToRGB = function(l, a, b) {}; - - return Convert; - - })(); - - Event = (function() { - function Event() {} - - Event.events = {}; - - Event.types = ["processStart", "processComplete", "renderStart", "renderFinished", "blockStarted", "blockFinished"]; - - Event.trigger = function(target, type, data) { - var event, _i, _len, _ref, _results; - if (this.events[type] && this.events[type].length) { - _ref = this.events[type]; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - event = _ref[_i]; - if (event.target === null || target.id === event.target.id) { - _results.push(event.fn.call(target, data)); - } else { - _results.push(void 0); - } - } - return _results; - } - }; - - Event.listen = function(target, type, fn) { - var _fn, _type; - if (typeof target === "string") { - _type = target; - _fn = type; - target = null; - type = _type; - fn = _fn; - } - if (__indexOf.call(this.types, type) < 0) { - return false; - } - if (!this.events[type]) { - this.events[type] = []; - } - this.events[type].push({ - target: target, - fn: fn - }); - return true; - }; - - return Event; - - })(); - - Caman.Event = Event; - - Caman.Filter = Filter = (function() { - function Filter() {} - - Filter.Type = { - Single: 1, - Kernel: 2, - LayerDequeue: 3, - LayerFinished: 4, - LoadOverlay: 5, - Plugin: 6 - }; - - Filter.register = function(name, filterFunc) { - return Caman.prototype[name] = filterFunc; - }; - - return Filter; - - })(); - - Caman.IO = IO = (function() { - function IO() {} - - IO.domainRegex = /(?:(?:http|https):\/\/)((?:\w+)\.(?:(?:\w|\.)+))/; - - IO.isRemote = function(img) { - if (img == null) { - return false; - } - if (this.corsEnabled(img)) { - return false; - } - return this.isURLRemote(img.src); - }; - - IO.corsEnabled = function(img) { - var _ref; - return (img.crossOrigin != null) && ((_ref = img.crossOrigin.toLowerCase()) === 'anonymous' || _ref === 'use-credentials'); - }; - - IO.isURLRemote = function(url) { - var matches; - matches = url.match(this.domainRegex); - if (matches) { - return matches[1] !== document.domain; - } else { - return false; - } - }; - - IO.remoteCheck = function(src) { - if (this.isURLRemote(src)) { - if (!Caman.remoteProxy.length) { - Log.info("Attempting to load a remote image without a configured proxy. URL: " + src); - } else { - if (Caman.isURLRemote(Caman.remoteProxy)) { - Log.info("Cannot use a remote proxy for loading images."); - return; - } - return "" + Caman.remoteProxy + "?camanProxyUrl=" + (encodeURIComponent(src)); - } - } - }; - - IO.proxyUrl = function(src) { - return "" + Caman.remoteProxy + "?" + Caman.proxyParam + "=" + (encodeURIComponent(src)); - }; - - IO.useProxy = function(lang) { - var langToExt; - langToExt = { - ruby: 'rb', - python: 'py', - perl: 'pl', - javascript: 'js' - }; - lang = lang.toLowerCase(); - if (langToExt[lang] != null) { - lang = langToExt[lang]; - } - return "proxies/caman_proxy." + lang; - }; - - return IO; - - })(); - - Caman.prototype.save = function() { - if (typeof exports !== "undefined" && exports !== null) { - return this.nodeSave.apply(this, arguments); - } else { - return this.browserSave.apply(this, arguments); - } - }; - - Caman.prototype.browserSave = function(type) { - var image; - if (type == null) { - type = "png"; - } - type = type.toLowerCase(); - image = this.toBase64(type).replace("image/" + type, "image/octet-stream"); - return document.location.href = image; - }; - - Caman.prototype.nodeSave = function(file, overwrite) { - var e, stats; - if (overwrite == null) { - overwrite = true; - } - try { - stats = fs.statSync(file); - if (stats.isFile() && !overwrite) { - return false; - } - } catch (_error) { - e = _error; - Log.debug("Creating output file " + file); - } - return fs.writeFile(file, this.canvas.toBuffer(), function() { - return Log.debug("Finished writing to " + file); - }); - }; - - Caman.prototype.toImage = function(type) { - var img; - img = document.createElement('img'); - img.src = this.toBase64(type); - img.width = this.dimensions.width; - img.height = this.dimensions.height; - if (window.devicePixelRatio) { - img.width /= window.devicePixelRatio; - img.height /= window.devicePixelRatio; - } - return img; - }; - - Caman.prototype.toBase64 = function(type) { - if (type == null) { - type = "png"; - } - type = type.toLowerCase(); - return this.canvas.toDataURL("image/" + type); - }; - - Layer = (function() { - function Layer(c) { - this.c = c; - this.filter = this.c; - this.options = { - blendingMode: 'normal', - opacity: 1.0 - }; - this.layerID = Util.uniqid.get(); - this.canvas = typeof exports !== "undefined" && exports !== null ? new Canvas() : document.createElement('canvas'); - this.canvas.width = this.c.dimensions.width; - this.canvas.height = this.c.dimensions.height; - this.context = this.canvas.getContext('2d'); - this.context.createImageData(this.canvas.width, this.canvas.height); - this.imageData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - this.pixelData = this.imageData.data; - } - - Layer.prototype.newLayer = function(cb) { - return this.c.newLayer.call(this.c, cb); - }; - - Layer.prototype.setBlendingMode = function(mode) { - this.options.blendingMode = mode; - return this; - }; - - Layer.prototype.opacity = function(opacity) { - this.options.opacity = opacity / 100; - return this; - }; - - Layer.prototype.copyParent = function() { - var i, parentData, _i, _ref; - parentData = this.c.pixelData; - for (i = _i = 0, _ref = this.c.pixelData.length; _i < _ref; i = _i += 4) { - this.pixelData[i] = parentData[i]; - this.pixelData[i + 1] = parentData[i + 1]; - this.pixelData[i + 2] = parentData[i + 2]; - this.pixelData[i + 3] = parentData[i + 3]; - } - return this; - }; - - Layer.prototype.fillColor = function() { - return this.c.fillColor.apply(this.c, arguments); - }; - - Layer.prototype.overlayImage = function(image) { - if (typeof image === "object") { - image = image.src; - } else if (typeof image === "string" && image[0] === "#") { - image = $(image).src; - } - if (!image) { - return this; - } - this.c.renderer.renderQueue.push({ - type: Filter.Type.LoadOverlay, - src: image, - layer: this - }); - return this; - }; - - Layer.prototype.applyToParent = function() { - var i, layerData, parentData, result, rgbaLayer, rgbaParent, _i, _ref, _results; - parentData = this.c.pixelStack[this.c.pixelStack.length - 1]; - layerData = this.c.pixelData; - _results = []; - for (i = _i = 0, _ref = layerData.length; _i < _ref; i = _i += 4) { - rgbaParent = { - r: parentData[i], - g: parentData[i + 1], - b: parentData[i + 2], - a: parentData[i + 3] - }; - rgbaLayer = { - r: layerData[i], - g: layerData[i + 1], - b: layerData[i + 2], - a: layerData[i + 3] - }; - result = Blender.execute(this.options.blendingMode, rgbaLayer, rgbaParent); - result.r = Util.clampRGB(result.r); - result.g = Util.clampRGB(result.g); - result.b = Util.clampRGB(result.b); - if (result.a == null) { - result.a = rgbaLayer.a; - } - parentData[i] = rgbaParent.r - ((rgbaParent.r - result.r) * (this.options.opacity * (result.a / 255))); - parentData[i + 1] = rgbaParent.g - ((rgbaParent.g - result.g) * (this.options.opacity * (result.a / 255))); - _results.push(parentData[i + 2] = rgbaParent.b - ((rgbaParent.b - result.b) * (this.options.opacity * (result.a / 255)))); - } - return _results; - }; - - return Layer; - - })(); - - Logger = (function() { - function Logger() { - var name, _i, _len, _ref; - _ref = ['log', 'info', 'warn', 'error']; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - name = _ref[_i]; - this[name] = (function(name) { - return function() { - var args, e; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - if (!Caman.DEBUG) { - return; - } - try { - return console[name].apply(console, args); - } catch (_error) { - e = _error; - return console[name](args); - } - }; - })(name); - } - this.debug = this.log; - } - - return Logger; - - })(); - - Log = new Logger(); - - PixelInfo = (function() { - PixelInfo.coordinatesToLocation = function(x, y, width) { - return (y * width + x) * 4; - }; - - PixelInfo.locationToCoordinates = function(loc, width) { - var x, y; - y = Math.floor(loc / (width * 4)); - x = (loc % (width * 4)) / 4; - return { - x: x, - y: y - }; - }; - - function PixelInfo(c) { - this.c = c; - this.loc = 0; - } - - PixelInfo.prototype.locationXY = function() { - var x, y; - y = this.c.dimensions.height - Math.floor(this.loc / (this.c.dimensions.width * 4)); - x = (this.loc % (this.c.dimensions.width * 4)) / 4; - return { - x: x, - y: y - }; - }; - - PixelInfo.prototype.getPixelRelative = function(horiz, vert) { - var newLoc; - newLoc = this.loc + (this.c.dimensions.width * 4 * (vert * -1)) + (4 * horiz); - if (newLoc > this.c.pixelData.length || newLoc < 0) { - return { - r: 0, - g: 0, - b: 0, - a: 0 - }; - } - return { - r: this.c.pixelData[newLoc], - g: this.c.pixelData[newLoc + 1], - b: this.c.pixelData[newLoc + 2], - a: this.c.pixelData[newLoc + 3] - }; - }; - - PixelInfo.prototype.putPixelRelative = function(horiz, vert, rgba) { - var nowLoc; - nowLoc = this.loc + (this.c.dimensions.width * 4 * (vert * -1)) + (4 * horiz); - if (newLoc > this.c.pixelData.length || newLoc < 0) { - return; - } - this.c.pixelData[newLoc] = rgba.r; - this.c.pixelData[newLoc + 1] = rgba.g; - this.c.pixelData[newLoc + 2] = rgba.b; - this.c.pixelData[newLoc + 3] = rgba.a; - return true; - }; - - PixelInfo.prototype.getPixel = function(x, y) { - var loc; - loc = this.coordinatesToLocation(x, y, this.width); - return { - r: this.c.pixelData[loc], - g: this.c.pixelData[loc + 1], - b: this.c.pixelData[loc + 2], - a: this.c.pixelData[loc + 3] - }; - }; - - PixelInfo.prototype.putPixel = function(x, y, rgba) { - var loc; - loc = this.coordinatesToLocation(x, y, this.width); - this.c.pixelData[loc] = rgba.r; - this.c.pixelData[loc + 1] = rgba.g; - this.c.pixelData[loc + 2] = rgba.b; - return this.c.pixelData[loc + 3] = rgba.a; - }; - - return PixelInfo; - - })(); - - Plugin = (function() { - function Plugin() {} - - Plugin.plugins = {}; - - Plugin.register = function(name, plugin) { - return this.plugins[name] = plugin; - }; - - Plugin.execute = function(context, name, args) { - return this.plugins[name].apply(context, args); - }; - - return Plugin; - - })(); - - Caman.Plugin = Plugin; - - Caman.Renderer = Renderer = (function() { - Renderer.Blocks = Caman.NodeJS ? require('os').cpus().length : 4; - - function Renderer(c) { - this.c = c; - this.processNext = __bind(this.processNext, this); - this.renderQueue = []; - this.modPixelData = null; - } - - Renderer.prototype.add = function(job) { - if (job == null) { - return; - } - return this.renderQueue.push(job); - }; - - Renderer.prototype.processNext = function() { - var layer; - if (this.renderQueue.length === 0) { - Event.trigger(this, "renderFinished"); - if (this.finishedFn != null) { - this.finishedFn.call(this.c); - } - return this; - } - this.currentJob = this.renderQueue.shift(); - switch (this.currentJob.type) { - case Filter.Type.LayerDequeue: - layer = this.c.canvasQueue.shift(); - this.c.executeLayer(layer); - return this.processNext(); - case Filter.Type.LayerFinished: - this.c.applyCurrentLayer(); - this.c.popContext(); - return this.processNext(); - case Filter.Type.LoadOverlay: - return this.loadOverlay(this.currentJob.layer, this.currentJob.src); - case Filter.Type.Plugin: - return this.executePlugin(); - default: - return this.executeFilter(); - } - }; - - Renderer.prototype.execute = function(callback) { - this.finishedFn = callback; - this.modPixelData = Util.dataArray(this.c.pixelData.length); - return this.processNext(); - }; - - Renderer.prototype.eachBlock = function(fn) { - var blockN, blockPixelLength, bnum, end, f, i, lastBlockN, n, start, _i, _ref, _results, - _this = this; - this.blocksDone = 0; - n = this.c.pixelData.length; - blockPixelLength = Math.floor((n / 4) / Renderer.Blocks); - blockN = blockPixelLength * 4; - lastBlockN = blockN + ((n / 4) % Renderer.Blocks) * 4; - _results = []; - for (i = _i = 0, _ref = Renderer.Blocks; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - start = i * blockN; - end = start + (i === Renderer.Blocks - 1 ? lastBlockN : blockN); - if (Caman.NodeJS) { - f = Fiber(function() { - return fn.call(_this, i, start, end); - }); - bnum = f.run(); - _results.push(this.blockFinished(bnum)); - } else { - _results.push(setTimeout((function(i, start, end) { - return function() { - return fn.call(_this, i, start, end); - }; - })(i, start, end), 0)); - } - } - return _results; - }; - - Renderer.prototype.executeFilter = function() { - Event.trigger(this.c, "processStart", this.currentJob); - if (this.currentJob.type === Filter.Type.Single) { - return this.eachBlock(this.renderBlock); - } else { - return this.eachBlock(this.renderKernel); - } - }; - - Renderer.prototype.executePlugin = function() { - Log.debug("Executing plugin " + this.currentJob.plugin); - Plugin.execute(this.c, this.currentJob.plugin, this.currentJob.args); - Log.debug("Plugin " + this.currentJob.plugin + " finished!"); - return this.processNext(); - }; - - Renderer.prototype.renderBlock = function(bnum, start, end) { - var data, i, pixelInfo, res, _i; - Log.debug("Block #" + bnum + " - Filter: " + this.currentJob.name + ", Start: " + start + ", End: " + end); - Event.trigger(this.c, "blockStarted", { - blockNum: bnum, - totalBlocks: Renderer.Blocks, - startPixel: start, - endPixel: end - }); - data = { - r: 0, - g: 0, - b: 0, - a: 0 - }; - pixelInfo = new PixelInfo(this.c); - for (i = _i = start; _i < end; i = _i += 4) { - pixelInfo.loc = i; - data.r = this.c.pixelData[i]; - data.g = this.c.pixelData[i + 1]; - data.b = this.c.pixelData[i + 2]; - data.a = this.c.pixelData[i + 3]; - res = this.currentJob.processFn.call(pixelInfo, data); - if (res.a == null) { - res.a = data.a; - } - this.c.pixelData[i] = Util.clampRGB(res.r); - this.c.pixelData[i + 1] = Util.clampRGB(res.g); - this.c.pixelData[i + 2] = Util.clampRGB(res.b); - this.c.pixelData[i + 3] = Util.clampRGB(res.a); - } - if (Caman.NodeJS) { - return Fiber["yield"](bnum); - } else { - return this.blockFinished(bnum); - } - }; - - Renderer.prototype.renderKernel = function(bnum, start, end) { - var adjust, adjustSize, bias, builder, builderIndex, divisor, i, j, k, kernel, n, name, pixel, pixelInfo, res, _i, _j, _k; - name = this.currentJob.name; - bias = this.currentJob.bias; - divisor = this.currentJob.divisor; - n = this.c.pixelData.length; - adjust = this.currentJob.adjust; - adjustSize = Math.sqrt(adjust.length); - kernel = []; - Log.debug("Rendering kernel - Filter: " + this.currentJob.name); - start = Math.max(start, this.c.dimensions.width * 4 * ((adjustSize - 1) / 2)); - end = Math.min(end, n - (this.c.dimensions.width * 4 * ((adjustSize - 1) / 2))); - builder = (adjustSize - 1) / 2; - pixelInfo = new PixelInfo(this.c); - for (i = _i = start; _i < end; i = _i += 4) { - pixelInfo.loc = i; - builderIndex = 0; - for (j = _j = -builder; -builder <= builder ? _j <= builder : _j >= builder; j = -builder <= builder ? ++_j : --_j) { - for (k = _k = builder; builder <= -builder ? _k <= -builder : _k >= -builder; k = builder <= -builder ? ++_k : --_k) { - pixel = pixelInfo.getPixelRelative(j, k); - kernel[builderIndex * 3] = pixel.r; - kernel[builderIndex * 3 + 1] = pixel.g; - kernel[builderIndex * 3 + 2] = pixel.b; - builderIndex++; - } - } - res = this.processKernel(adjust, kernel, divisor, bias); - this.modPixelData[i] = Util.clampRGB(res.r); - this.modPixelData[i + 1] = Util.clampRGB(res.g); - this.modPixelData[i + 2] = Util.clampRGB(res.b); - this.modPixelData[i + 3] = this.c.pixelData[i + 3]; - } - if (Caman.NodeJS) { - return Fiber["yield"](bnum); - } else { - return this.blockFinished(bnum); - } - }; - - Renderer.prototype.blockFinished = function(bnum) { - var i, _i, _ref; - if (bnum >= 0) { - Log.debug("Block #" + bnum + " finished! Filter: " + this.currentJob.name); - } - this.blocksDone++; - Event.trigger(this.c, "blockFinished", { - blockNum: bnum, - blocksFinished: this.blocksDone, - totalBlocks: Renderer.Blocks - }); - if (this.blocksDone === Renderer.Blocks) { - if (this.currentJob.type === Filter.Type.Kernel) { - for (i = _i = 0, _ref = this.c.pixelData.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - this.c.pixelData[i] = this.modPixelData[i]; - } - } - if (bnum >= 0) { - Log.debug("Filter " + this.currentJob.name + " finished!"); - } - Event.trigger(this.c, "processComplete", this.currentJob); - return this.processNext(); - } - }; - - Renderer.prototype.processKernel = function(adjust, kernel, divisor, bias) { - var i, val, _i, _ref; - val = { - r: 0, - g: 0, - b: 0 - }; - for (i = _i = 0, _ref = adjust.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - val.r += adjust[i] * kernel[i * 3]; - val.g += adjust[i] * kernel[i * 3 + 1]; - val.b += adjust[i] * kernel[i * 3 + 2]; - } - val.r = (val.r / divisor) + bias; - val.g = (val.g / divisor) + bias; - val.b = (val.b / divisor) + bias; - return val; - }; - - Renderer.prototype.loadOverlay = function(layer, src) { - var img, proxyUrl, - _this = this; - img = document.createElement('img'); - img.onload = function() { - layer.context.drawImage(img, 0, 0, _this.c.dimensions.width, _this.c.dimensions.height); - layer.imageData = layer.context.getImageData(0, 0, _this.c.dimensions.width, _this.c.dimensions.height); - layer.pixelData = layer.imageData.data; - _this.c.pixelData = layer.pixelData; - return _this.processNext(); - }; - proxyUrl = IO.remoteCheck(src); - return img.src = proxyUrl != null ? proxyUrl : src; - }; - - return Renderer; - - })(); - - Caman.Store = Store = (function() { - function Store() {} - - Store.items = {}; - - Store.has = function(search) { - return this.items[search] != null; - }; - - Store.get = function(search) { - return this.items[search]; - }; - - Store.put = function(name, obj) { - return this.items[name] = obj; - }; - - Store.execute = function(search, callback) { - var _this = this; - setTimeout(function() { - return callback.call(_this.get(search), _this.get(search)); - }, 0); - return this.get(search); - }; - - Store.flush = function(name) { - if (name == null) { - name = false; - } - if (name) { - return delete this.items[name]; - } else { - return this.items = {}; - } - }; - - return Store; - - })(); - - Blender.register("normal", function(rgbaLayer, rgbaParent) { - return { - r: rgbaLayer.r, - g: rgbaLayer.g, - b: rgbaLayer.b - }; - }); - - Blender.register("multiply", function(rgbaLayer, rgbaParent) { - return { - r: (rgbaLayer.r * rgbaParent.r) / 255, - g: (rgbaLayer.g * rgbaParent.g) / 255, - b: (rgbaLayer.b * rgbaParent.b) / 255 - }; - }); - - Blender.register("screen", function(rgbaLayer, rgbaParent) { - return { - r: 255 - (((255 - rgbaLayer.r) * (255 - rgbaParent.r)) / 255), - g: 255 - (((255 - rgbaLayer.g) * (255 - rgbaParent.g)) / 255), - b: 255 - (((255 - rgbaLayer.b) * (255 - rgbaParent.b)) / 255) - }; - }); - - Blender.register("overlay", function(rgbaLayer, rgbaParent) { - var result; - result = {}; - result.r = rgbaParent.r > 128 ? 255 - 2 * (255 - rgbaLayer.r) * (255 - rgbaParent.r) / 255 : (rgbaParent.r * rgbaLayer.r * 2) / 255; - result.g = rgbaParent.g > 128 ? 255 - 2 * (255 - rgbaLayer.g) * (255 - rgbaParent.g) / 255 : (rgbaParent.g * rgbaLayer.g * 2) / 255; - result.b = rgbaParent.b > 128 ? 255 - 2 * (255 - rgbaLayer.b) * (255 - rgbaParent.b) / 255 : (rgbaParent.b * rgbaLayer.b * 2) / 255; - return result; - }); - - Blender.register("difference", function(rgbaLayer, rgbaParent) { - return { - r: rgbaLayer.r - rgbaParent.r, - g: rgbaLayer.g - rgbaParent.g, - b: rgbaLayer.b - rgbaParent.b - }; - }); - - Blender.register("addition", function(rgbaLayer, rgbaParent) { - return { - r: rgbaParent.r + rgbaLayer.r, - g: rgbaParent.g + rgbaLayer.g, - b: rgbaParent.b + rgbaLayer.b - }; - }); - - Blender.register("exclusion", function(rgbaLayer, rgbaParent) { - return { - r: 128 - 2 * (rgbaParent.r - 128) * (rgbaLayer.r - 128) / 255, - g: 128 - 2 * (rgbaParent.g - 128) * (rgbaLayer.g - 128) / 255, - b: 128 - 2 * (rgbaParent.b - 128) * (rgbaLayer.b - 128) / 255 - }; - }); - - Blender.register("softLight", function(rgbaLayer, rgbaParent) { - var result; - result = {}; - result.r = rgbaParent.r > 128 ? 255 - ((255 - rgbaParent.r) * (255 - (rgbaLayer.r - 128))) / 255 : (rgbaParent.r * (rgbaLayer.r + 128)) / 255; - result.g = rgbaParent.g > 128 ? 255 - ((255 - rgbaParent.g) * (255 - (rgbaLayer.g - 128))) / 255 : (rgbaParent.g * (rgbaLayer.g + 128)) / 255; - result.b = rgbaParent.b > 128 ? 255 - ((255 - rgbaParent.b) * (255 - (rgbaLayer.b - 128))) / 255 : (rgbaParent.b * (rgbaLayer.b + 128)) / 255; - return result; - }); - - Blender.register("lighten", function(rgbaLayer, rgbaParent) { - return { - r: rgbaParent.r > rgbaLayer.r ? rgbaParent.r : rgbaLayer.r, - g: rgbaParent.g > rgbaLayer.g ? rgbaParent.g : rgbaLayer.g, - b: rgbaParent.b > rgbaLayer.b ? rgbaParent.b : rgbaLayer.b - }; - }); - - Blender.register("darken", function(rgbaLayer, rgbaParent) { - return { - r: rgbaParent.r > rgbaLayer.r ? rgbaLayer.r : rgbaParent.r, - g: rgbaParent.g > rgbaLayer.g ? rgbaLayer.g : rgbaParent.g, - b: rgbaParent.b > rgbaLayer.b ? rgbaLayer.b : rgbaParent.b - }; - }); - - Filter.register("fillColor", function() { - var color; - if (arguments.length === 1) { - color = Convert.hexToRGB(arguments[0]); - } else { - color = { - r: arguments[0], - g: arguments[1], - b: arguments[2] - }; - } - return this.process("fillColor", function(rgba) { - rgba.r = color.r; - rgba.g = color.g; - rgba.b = color.b; - rgba.a = 255; - return rgba; - }); - }); - - Filter.register("brightness", function(adjust) { - adjust = Math.floor(255 * (adjust / 100)); - return this.process("brightness", function(rgba) { - rgba.r += adjust; - rgba.g += adjust; - rgba.b += adjust; - return rgba; - }); - }); - - Filter.register("saturation", function(adjust) { - adjust *= -0.01; - return this.process("saturation", function(rgba) { - var max; - max = Math.max(rgba.r, rgba.g, rgba.b); - if (rgba.r !== max) { - rgba.r += (max - rgba.r) * adjust; - } - if (rgba.g !== max) { - rgba.g += (max - rgba.g) * adjust; - } - if (rgba.b !== max) { - rgba.b += (max - rgba.b) * adjust; - } - return rgba; - }); - }); - - Filter.register("vibrance", function(adjust) { - adjust *= -1; - return this.process("vibrance", function(rgba) { - var amt, avg, max; - max = Math.max(rgba.r, rgba.g, rgba.b); - avg = (rgba.r + rgba.g + rgba.b) / 3; - amt = ((Math.abs(max - avg) * 2 / 255) * adjust) / 100; - if (rgba.r !== max) { - rgba.r += (max - rgba.r) * amt; - } - if (rgba.g !== max) { - rgba.g += (max - rgba.g) * amt; - } - if (rgba.b !== max) { - rgba.b += (max - rgba.b) * amt; - } - return rgba; - }); - }); - - Filter.register("greyscale", function(adjust) { - return this.process("greyscale", function(rgba) { - var avg; - avg = Calculate.luminance(rgba); - rgba.r = avg; - rgba.g = avg; - rgba.b = avg; - return rgba; - }); - }); - - Filter.register("contrast", function(adjust) { - adjust = Math.pow((adjust + 100) / 100, 2); - return this.process("contrast", function(rgba) { - rgba.r /= 255; - rgba.r -= 0.5; - rgba.r *= adjust; - rgba.r += 0.5; - rgba.r *= 255; - rgba.g /= 255; - rgba.g -= 0.5; - rgba.g *= adjust; - rgba.g += 0.5; - rgba.g *= 255; - rgba.b /= 255; - rgba.b -= 0.5; - rgba.b *= adjust; - rgba.b += 0.5; - rgba.b *= 255; - return rgba; - }); - }); - - Filter.register("hue", function(adjust) { - return this.process("hue", function(rgba) { - var h, hsv, rgb; - hsv = Convert.rgbToHSV(rgba.r, rgba.g, rgba.b); - h = hsv.h * 100; - h += Math.abs(adjust); - h = h % 100; - h /= 100; - hsv.h = h; - rgb = Convert.hsvToRGB(hsv.h, hsv.s, hsv.v); - rgb.a = rgba.a; - return rgb; - }); - }); - - Filter.register("colorize", function() { - var level, rgb; - if (arguments.length === 2) { - rgb = Convert.hexToRGB(arguments[0]); - level = arguments[1]; - } else if (arguments.length === 4) { - rgb = { - r: arguments[0], - g: arguments[1], - b: arguments[2] - }; - level = arguments[3]; - } - return this.process("colorize", function(rgba) { - rgba.r -= (rgba.r - rgb.r) * (level / 100); - rgba.g -= (rgba.g - rgb.g) * (level / 100); - rgba.b -= (rgba.b - rgb.b) * (level / 100); - return rgba; - }); - }); - - Filter.register("invert", function() { - return this.process("invert", function(rgba) { - rgba.r = 255 - rgba.r; - rgba.g = 255 - rgba.g; - rgba.b = 255 - rgba.b; - return rgba; - }); - }); - - Filter.register("sepia", function(adjust) { - if (adjust == null) { - adjust = 100; - } - adjust /= 100; - return this.process("sepia", function(rgba) { - rgba.r = Math.min(255, (rgba.r * (1 - (0.607 * adjust))) + (rgba.g * (0.769 * adjust)) + (rgba.b * (0.189 * adjust))); - rgba.g = Math.min(255, (rgba.r * (0.349 * adjust)) + (rgba.g * (1 - (0.314 * adjust))) + (rgba.b * (0.168 * adjust))); - rgba.b = Math.min(255, (rgba.r * (0.272 * adjust)) + (rgba.g * (0.534 * adjust)) + (rgba.b * (1 - (0.869 * adjust)))); - return rgba; - }); - }); - - Filter.register("gamma", function(adjust) { - return this.process("gamma", function(rgba) { - rgba.r = Math.pow(rgba.r / 255, adjust) * 255; - rgba.g = Math.pow(rgba.g / 255, adjust) * 255; - rgba.b = Math.pow(rgba.b / 255, adjust) * 255; - return rgba; - }); - }); - - Filter.register("noise", function(adjust) { - adjust = Math.abs(adjust) * 2.55; - return this.process("noise", function(rgba) { - var rand; - rand = Calculate.randomRange(adjust * -1, adjust); - rgba.r += rand; - rgba.g += rand; - rgba.b += rand; - return rgba; - }); - }); - - Filter.register("clip", function(adjust) { - adjust = Math.abs(adjust) * 2.55; - return this.process("clip", function(rgba) { - if (rgba.r > 255 - adjust) { - rgba.r = 255; - } else if (rgba.r < adjust) { - rgba.r = 0; - } - if (rgba.g > 255 - adjust) { - rgba.g = 255; - } else if (rgba.g < adjust) { - rgba.g = 0; - } - if (rgba.b > 255 - adjust) { - rgba.b = 255; - } else if (rgba.b < adjust) { - rgba.b = 0; - } - return rgba; - }); - }); - - Filter.register("channels", function(options) { - var chan, value; - if (typeof options !== "object") { - return this; - } - for (chan in options) { - if (!__hasProp.call(options, chan)) continue; - value = options[chan]; - if (value === 0) { - delete options[chan]; - continue; - } - options[chan] /= 100; - } - if (options.length === 0) { - return this; - } - return this.process("channels", function(rgba) { - if (options.red != null) { - if (options.red > 0) { - rgba.r += (255 - rgba.r) * options.red; - } else { - rgba.r -= rgba.r * Math.abs(options.red); - } - } - if (options.green != null) { - if (options.green > 0) { - rgba.g += (255 - rgba.g) * options.green; - } else { - rgba.g -= rgba.g * Math.abs(options.green); - } - } - if (options.blue != null) { - if (options.blue > 0) { - rgba.b += (255 - rgba.b) * options.blue; - } else { - rgba.b -= rgba.b * Math.abs(options.blue); - } - } - return rgba; - }); - }); - - Filter.register("curves", function() { - var bezier, chans, cps, ctrl1, ctrl2, end, i, start, _i, _j, _ref, _ref1; - chans = arguments[0], cps = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - if (typeof chans === "string") { - chans = chans.split(""); - } - if (chans[0] === "v") { - chans = ['r', 'g', 'b']; - } - if (cps.length < 3 || cps.length > 4) { - throw "Invalid number of arguments to curves filter"; - } - start = cps[0]; - ctrl1 = cps[1]; - ctrl2 = cps.length === 4 ? cps[2] : cps[1]; - end = cps[cps.length - 1]; - bezier = Calculate.bezier(start, ctrl1, ctrl2, end, 0, 255); - if (start[0] > 0) { - for (i = _i = 0, _ref = start[0]; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - bezier[i] = start[1]; - } - } - if (end[0] < 255) { - for (i = _j = _ref1 = end[0]; _ref1 <= 255 ? _j <= 255 : _j >= 255; i = _ref1 <= 255 ? ++_j : --_j) { - bezier[i] = end[1]; - } - } - return this.process("curves", function(rgba) { - var _k, _ref2; - for (i = _k = 0, _ref2 = chans.length; 0 <= _ref2 ? _k < _ref2 : _k > _ref2; i = 0 <= _ref2 ? ++_k : --_k) { - rgba[chans[i]] = bezier[rgba[chans[i]]]; - } - return rgba; - }); - }); - - Filter.register("exposure", function(adjust) { - var ctrl1, ctrl2, p; - p = Math.abs(adjust) / 100; - ctrl1 = [0, 255 * p]; - ctrl2 = [255 - (255 * p), 255]; - if (adjust < 0) { - ctrl1 = ctrl1.reverse(); - ctrl2 = ctrl2.reverse(); - } - return this.curves('rgb', [0, 0], ctrl1, ctrl2, [255, 255]); - }); - - Caman.Plugin.register("crop", function(width, height, x, y) { - var canvas, ctx; - if (x == null) { - x = 0; - } - if (y == null) { - y = 0; - } - if (typeof exports !== "undefined" && exports !== null) { - canvas = new Canvas(width, height); - } else { - canvas = document.createElement('canvas'); - Util.copyAttributes(this.canvas, canvas); - canvas.width = width; - canvas.height = height; - } - ctx = canvas.getContext('2d'); - ctx.drawImage(this.canvas, x, y, width, height, 0, 0, width, height); - this.cropCoordinates = { - x: x, - y: y - }; - this.cropped = true; - return this.replaceCanvas(canvas); - }); - - Caman.Plugin.register("resize", function(newDims) { - var canvas, ctx; - if (newDims == null) { - newDims = null; - } - if (newDims === null || ((newDims.width == null) && (newDims.height == null))) { - Log.error("Invalid or missing dimensions given for resize"); - return; - } - if (newDims.width == null) { - newDims.width = this.canvas.width * newDims.height / this.canvas.height; - } else if (newDims.height == null) { - newDims.height = this.canvas.height * newDims.width / this.canvas.width; - } - if (typeof exports !== "undefined" && exports !== null) { - canvas = new Canvas(newDims.width, newDims.height); - } else { - canvas = document.createElement('canvas'); - Util.copyAttributes(this.canvas, canvas); - canvas.width = newDims.width; - canvas.height = newDims.height; - } - ctx = canvas.getContext('2d'); - ctx.drawImage(this.canvas, 0, 0, this.canvas.width, this.canvas.height, 0, 0, newDims.width, newDims.height); - this.resized = true; - return this.replaceCanvas(canvas); - }); - - Caman.Filter.register("crop", function() { - return this.processPlugin("crop", Array.prototype.slice.call(arguments, 0)); - }); - - Caman.Filter.register("resize", function() { - return this.processPlugin("resize", Array.prototype.slice.call(arguments, 0)); - }); - -}).call(this); diff --git a/mig/images/lib/CamanJS-4.1.1/docs/analyze.html b/mig/images/lib/CamanJS-4.1.1/docs/analyze.html deleted file mode 100644 index ab8dbe728..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/analyze.html +++ /dev/null @@ -1,257 +0,0 @@ - - - - - analyze.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/autoload.html b/mig/images/lib/CamanJS-4.1.1/docs/autoload.html deleted file mode 100644 index b6014982a..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/autoload.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - autoload.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/blender.html b/mig/images/lib/CamanJS-4.1.1/docs/blender.html deleted file mode 100644 index e57ec46ab..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/blender.html +++ /dev/null @@ -1,224 +0,0 @@ - - - - - blender.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/blenders.html b/mig/images/lib/CamanJS-4.1.1/docs/blenders.html deleted file mode 100644 index 9e30945eb..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/blenders.html +++ /dev/null @@ -1,281 +0,0 @@ - - - - - blenders.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/blur.html b/mig/images/lib/CamanJS-4.1.1/docs/blur.html deleted file mode 100644 index 6674496d8..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/blur.html +++ /dev/null @@ -1,256 +0,0 @@ - - - - - blur.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/calculate.html b/mig/images/lib/CamanJS-4.1.1/docs/calculate.html deleted file mode 100644 index fba50e54c..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/calculate.html +++ /dev/null @@ -1,390 +0,0 @@ - - - - - calculate.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/caman.html b/mig/images/lib/CamanJS-4.1.1/docs/caman.html deleted file mode 100644 index 76ec316f0..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/caman.html +++ /dev/null @@ -1,1091 +0,0 @@ - - - - - caman.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/camera.html b/mig/images/lib/CamanJS-4.1.1/docs/camera.html deleted file mode 100644 index 7a131e8f4..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/camera.html +++ /dev/null @@ -1,484 +0,0 @@ - - - - - camera.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/compoundBlur.html b/mig/images/lib/CamanJS-4.1.1/docs/compoundBlur.html deleted file mode 100644 index 926070735..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/compoundBlur.html +++ /dev/null @@ -1,542 +0,0 @@ - - - - - # - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/convert.html b/mig/images/lib/CamanJS-4.1.1/docs/convert.html deleted file mode 100644 index 467e213c2..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/convert.html +++ /dev/null @@ -1,680 +0,0 @@ - - - - - convert.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/docco.css b/mig/images/lib/CamanJS-4.1.1/docs/docco.css deleted file mode 100644 index e92ceffae..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/docco.css +++ /dev/null @@ -1,354 +0,0 @@ -/*--------------------- Layout and Typography ----------------------------*/ -html { height: 100%; } -body { - font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; - font-size: 14px; - line-height: 16px; - color: #252519; - margin: 0; padding: 0; - height:100%; -} -#container { min-height: 100%; } - -a { - color: #261a3b; -} - -a:visited { - color: #261a3b; -} - -p, ul, ol { - margin: 0 0 15px; -} - -h1, h2, h3, h4, h5, h6 { - margin: 30px 0 15px 0; -} - -h1 { - margin-top: 40px; -} - -hr { - border: 0 none; - border-top: 1px solid #e5e5ee; - height: 1px; - margin: 20px 0; -} - -pre, tt, code { - font-size: 12px; line-height: 16px; - font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; - margin: 0; padding: 0; -} - -ul.sections { - list-style: none; - padding:0 0 5px 0;; - margin:0; -} - -/* - Force border-box so that % widths fit the parent - container without overlap because of margin/padding. - - More Info : http://www.quirksmode.org/css/box.html -*/ -ul.sections > li > div { - -moz-box-sizing: border-box; /* firefox */ - -ms-box-sizing: border-box; /* ie */ - -webkit-box-sizing: border-box; /* webkit */ - -khtml-box-sizing: border-box; /* konqueror */ - box-sizing: border-box; /* css3 */ -} - - -/*---------------------- Jump Page -----------------------------*/ -#jump_to, #jump_page { - margin: 0; - background: white; - -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; - -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; - font: 16px Arial; - cursor: pointer; - text-align: right; - list-style: none; -} - -#jump_to a { - text-decoration: none; -} - -#jump_to a.large { - display: none; -} -#jump_to a.small { - font-size: 22px; - font-weight: bold; - color: #676767; -} - -#jump_to, #jump_wrapper { - position: fixed; - right: 0; top: 0; - padding: 10px 15px; - margin:0; -} - -#jump_wrapper { - display: none; - padding:0; -} - -#jump_to:hover #jump_wrapper { - display: block; -} - -#jump_page { - padding: 5px 0 3px; - margin: 0 0 25px 25px; -} - -#jump_page .source { - display: block; - padding: 15px; - text-decoration: none; - border-top: 1px solid #eee; -} - -#jump_page .source:hover { - background: #f5f5ff; -} - -#jump_page .source:first-child { -} - -/*---------------------- Low resolutions (> 320px) ---------------------*/ -@media only screen and (min-width: 320px) { - .pilwrap { display: none; } - - ul.sections > li > div { - display: block; - padding:5px 10px 0 10px; - } - - ul.sections > li > div.annotation { - background: #fff; - } - - ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { - padding-left: 30px; - } - - ul.sections > li > div.content { - background: #f5f5ff; - overflow-x:auto; - -webkit-box-shadow: inset 0 0 5px #e5e5ee; - box-shadow: inset 0 0 5px #e5e5ee; - border: 1px solid #dedede; - margin:5px 10px 5px 10px; - padding-bottom: 5px; - } - - ul.sections > li > div.annotation pre { - margin: 7px 0 7px; - padding-left: 15px; - } - - ul.sections > li > div.annotation p tt, .annotation code { - background: #f8f8ff; - border: 1px solid #dedede; - font-size: 12px; - padding: 0 0.2em; - } -} - -/*---------------------- (> 481px) ---------------------*/ -@media only screen and (min-width: 481px) { - #container { - position: relative; - } - body { - background-color: #F5F5FF; - font-size: 15px; - line-height: 22px; - } - pre, tt, code { - line-height: 18px; - } - - #jump_to { - padding: 5px 10px; - } - #jump_wrapper { - padding: 0; - } - #jump_to, #jump_page { - font: 10px Arial; - text-transform: uppercase; - } - #jump_page .source { - padding: 5px 10px; - } - #jump_to a.large { - display: inline-block; - } - #jump_to a.small { - display: none; - } - - - - #background { - position: absolute; - top: 0; bottom: 0; - width: 350px; - background: #ffffff; - border-right: 1px solid #e5e5ee; - z-index: -1; - } - - ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { - padding-left: 40px; - } - - ul.sections > li { - white-space: nowrap; - } - - ul.sections > li > div { - display: inline-block; - } - - ul.sections > li > div.annotation { - max-width: 350px; - min-width: 350px; - min-height: 5px; - padding: 13px; - overflow-x: hidden; - white-space: normal; - vertical-align: top; - text-align: left; - } - ul.sections > li > div.annotation pre { - margin: 15px 0 15px; - padding-left: 15px; - } - - ul.sections > li > div.content { - padding: 13px; - vertical-align: top; - background: #f5f5ff; - border: none; - -webkit-box-shadow: none; - box-shadow: none; - } - - .pilwrap { - position: relative; - display: inline; - } - - .pilcrow { - font: 12px Arial; - text-decoration: none; - color: #454545; - position: absolute; - top: 3px; left: -20px; - padding: 1px 2px; - opacity: 0; - -webkit-transition: opacity 0.2s linear; - } - .for-h1 .pilcrow { - top: 47px; - } - .for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow { - top: 35px; - } - - ul.sections > li > div.annotation:hover .pilcrow { - opacity: 1; - } -} - -/*---------------------- (> 1025px) ---------------------*/ -@media only screen and (min-width: 1025px) { - - #background { - width: 525px; - } - ul.sections > li > div.annotation { - max-width: 525px; - min-width: 525px; - padding: 10px 25px 1px 50px; - } - ul.sections > li > div.content { - padding: 9px 15px 16px 25px; - } -} - -/*---------------------- Syntax Highlighting -----------------------------*/ -td.linenos { background-color: #f0f0f0; padding-right: 10px; } -span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } -body .hll { background-color: #ffffcc } -body .c { color: #408080; font-style: italic } /* Comment */ -body .err { border: 1px solid #FF0000 } /* Error */ -body .k { color: #954121 } /* Keyword */ -body .o { color: #666666 } /* Operator */ -body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ -body .cp { color: #BC7A00 } /* Comment.Preproc */ -body .c1 { color: #408080; font-style: italic } /* Comment.Single */ -body .cs { color: #408080; font-style: italic } /* Comment.Special */ -body .gd { color: #A00000 } /* Generic.Deleted */ -body .ge { font-style: italic } /* Generic.Emph */ -body .gr { color: #FF0000 } /* Generic.Error */ -body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -body .gi { color: #00A000 } /* Generic.Inserted */ -body .go { color: #808080 } /* Generic.Output */ -body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -body .gs { font-weight: bold } /* Generic.Strong */ -body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -body .gt { color: #0040D0 } /* Generic.Traceback */ -body .kc { color: #954121 } /* Keyword.Constant */ -body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ -body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ -body .kp { color: #954121 } /* Keyword.Pseudo */ -body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ -body .kt { color: #B00040 } /* Keyword.Type */ -body .m { color: #666666 } /* Literal.Number */ -body .s { color: #219161 } /* Literal.String */ -body .na { color: #7D9029 } /* Name.Attribute */ -body .nb { color: #954121 } /* Name.Builtin */ -body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ -body .no { color: #880000 } /* Name.Constant */ -body .nd { color: #AA22FF } /* Name.Decorator */ -body .ni { color: #999999; font-weight: bold } /* Name.Entity */ -body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ -body .nf { color: #0000FF } /* Name.Function */ -body .nl { color: #A0A000 } /* Name.Label */ -body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ -body .nt { color: #954121; font-weight: bold } /* Name.Tag */ -body .nv { color: #19469D } /* Name.Variable */ -body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ -body .w { color: #bbbbbb } /* Text.Whitespace */ -body .mf { color: #666666 } /* Literal.Number.Float */ -body .mh { color: #666666 } /* Literal.Number.Hex */ -body .mi { color: #666666 } /* Literal.Number.Integer */ -body .mo { color: #666666 } /* Literal.Number.Oct */ -body .sb { color: #219161 } /* Literal.String.Backtick */ -body .sc { color: #219161 } /* Literal.String.Char */ -body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ -body .s2 { color: #219161 } /* Literal.String.Double */ -body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ -body .sh { color: #219161 } /* Literal.String.Heredoc */ -body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ -body .sx { color: #954121 } /* Literal.String.Other */ -body .sr { color: #BB6688 } /* Literal.String.Regex */ -body .s1 { color: #219161 } /* Literal.String.Single */ -body .ss { color: #19469D } /* Literal.String.Symbol */ -body .bp { color: #954121 } /* Name.Builtin.Pseudo */ -body .vc { color: #19469D } /* Name.Variable.Class */ -body .vg { color: #19469D } /* Name.Variable.Global */ -body .vi { color: #19469D } /* Name.Variable.Instance */ -body .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/mig/images/lib/CamanJS-4.1.1/docs/edges.html b/mig/images/lib/CamanJS-4.1.1/docs/edges.html deleted file mode 100644 index 37b83ae6d..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/edges.html +++ /dev/null @@ -1,207 +0,0 @@ - - - - - edges.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/event.html b/mig/images/lib/CamanJS-4.1.1/docs/event.html deleted file mode 100644 index 07f9c9e05..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/event.html +++ /dev/null @@ -1,297 +0,0 @@ - - - - - event.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/filter.html b/mig/images/lib/CamanJS-4.1.1/docs/filter.html deleted file mode 100644 index 1eecaee3d..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/filter.html +++ /dev/null @@ -1,227 +0,0 @@ - - - - - filter.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/filters.html b/mig/images/lib/CamanJS-4.1.1/docs/filters.html deleted file mode 100644 index e56e77fc7..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/filters.html +++ /dev/null @@ -1,892 +0,0 @@ - - - - - filters.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/io.html b/mig/images/lib/CamanJS-4.1.1/docs/io.html deleted file mode 100644 index 7df604120..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/io.html +++ /dev/null @@ -1,356 +0,0 @@ - - - - - io.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/layer.html b/mig/images/lib/CamanJS-4.1.1/docs/layer.html deleted file mode 100644 index 82758e73b..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/layer.html +++ /dev/null @@ -1,433 +0,0 @@ - - - - - layer.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/logger.html b/mig/images/lib/CamanJS-4.1.1/docs/logger.html deleted file mode 100644 index e50af8cd1..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/logger.html +++ /dev/null @@ -1,217 +0,0 @@ - - - - - logger.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/pixelInfo.html b/mig/images/lib/CamanJS-4.1.1/docs/pixelInfo.html deleted file mode 100644 index bbe178d3a..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/pixelInfo.html +++ /dev/null @@ -1,339 +0,0 @@ - - - - - pixelinfo.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/plugin.html b/mig/images/lib/CamanJS-4.1.1/docs/plugin.html deleted file mode 100644 index a840741a2..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/plugin.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - - plugin.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/posterize.html b/mig/images/lib/CamanJS-4.1.1/docs/posterize.html deleted file mode 100644 index 88d324e15..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/posterize.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - posterize.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/presets.html b/mig/images/lib/CamanJS-4.1.1/docs/presets.html deleted file mode 100644 index 309caf595..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/presets.html +++ /dev/null @@ -1,443 +0,0 @@ - - - - - presets.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/renderer.html b/mig/images/lib/CamanJS-4.1.1/docs/renderer.html deleted file mode 100644 index f4969bf90..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/renderer.html +++ /dev/null @@ -1,551 +0,0 @@ - - - - - renderer.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/size.html b/mig/images/lib/CamanJS-4.1.1/docs/size.html deleted file mode 100644 index baccb7092..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/size.html +++ /dev/null @@ -1,345 +0,0 @@ - - - - - size.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/stackBlur.html b/mig/images/lib/CamanJS-4.1.1/docs/stackBlur.html deleted file mode 100644 index 04c316b1c..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/stackBlur.html +++ /dev/null @@ -1,432 +0,0 @@ - - - - - # - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/store.html b/mig/images/lib/CamanJS-4.1.1/docs/store.html deleted file mode 100644 index 3a6950b98..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/store.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - store.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/threshold.html b/mig/images/lib/CamanJS-4.1.1/docs/threshold.html deleted file mode 100644 index 570e7fb82..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/threshold.html +++ /dev/null @@ -1,201 +0,0 @@ - - - - - threshold.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/docs/util.html b/mig/images/lib/CamanJS-4.1.1/docs/util.html deleted file mode 100644 index 2f7da7a5f..000000000 --- a/mig/images/lib/CamanJS-4.1.1/docs/util.html +++ /dev/null @@ -1,295 +0,0 @@ - - - - - util.coffee - - - - - -
-
- - - - -
- - diff --git a/mig/images/lib/CamanJS-4.1.1/package.json b/mig/images/lib/CamanJS-4.1.1/package.json deleted file mode 100644 index 2d6e61e6a..000000000 --- a/mig/images/lib/CamanJS-4.1.1/package.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "name": "caman", - "version": "4.1.1", - "description": "Javascript (Ca)nvas (Man)ipulation for NodeJS and the browser", - "keywords": ["canvas", "image", "manipulate", "filter", "image manipulation", "editing"], - "homepage": "http://camanjs.com", - "author": { - "name": "Ryan LeFevre", - "email": "meltingice8917@gmail.com", - "url": "http://meltingice.net" - }, - "engines": { - "node": ">= 0.6.18" - }, - "contributors": [ - { - "name": "Rick Waldron", - "url": "http://github.com/rwldrn" - }, - { - "name": "Cezar Sa Espinola", - "url": "http://github.com/cezarsa" - }, - { - "name": "Jarques Pretorius", - "url": "http://twitter.com/jarques" - }, - { - "name": "Hosselaer", - "url": "https://github.com/Hosselaer" - }, - { - "name": "Mario Klingemann", - "url": "http://www.quasimondo.com" - } - ], - "main": "./dist/caman.full.js", - "repository": { - "type": "git", - "url": "http://github.com/meltingice/CamanJS.git" - }, - "dependencies": { - "canvas": ">= 1.6.11", - "fibers": "*" - }, - "devDependencies": { - "coffee-script": ">= 1.6.1", - "docco": "0.6.0", - "jsmin": "*", - "packer": "*", - "mocha": "*", - "chai": "*", - "servedir": "*", - "cli": ">= 1.0.0", - "cli-table": "*" - }, - "scripts": { - "test": "./node_modules/mocha/bin/mocha --compilers coffee:coffee-script --reporter spec --globals Caman ./test/unit/*.coffee", - "examples": "./node_modules/servedir/bin/servedir" - } -} diff --git a/mig/images/lib/CamanJS-4.1.1/proxies/caman_proxy.php b/mig/images/lib/CamanJS-4.1.1/proxies/caman_proxy.php deleted file mode 100644 index d99513535..000000000 --- a/mig/images/lib/CamanJS-4.1.1/proxies/caman_proxy.php +++ /dev/null @@ -1,35 +0,0 @@ - - - calculateLevels: -> - levels = - r: {} - g: {} - b: {} - - # Initialize all values to 0 first so there are no data gaps - for i in [0..255] - levels.r[i] = 0 - levels.g[i] = 0 - levels.b[i] = 0 - - # Iterate through each pixel block and increment the level counters - for i in [0...@c.pixelData.length] by 4 - levels.r[@c.pixelData[i]]++ - levels.g[@c.pixelData[i+1]]++ - levels.b[@c.pixelData[i+2]]++ - - # Normalize all of the numbers by converting them to percentages between - # 0 and 1.0 - numPixels = @c.pixelData.length / 4 - - for i in [0..255] - levels.r[i] /= numPixels - levels.g[i] /= numPixels - levels.b[i] /= numPixels - - levels \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/autoload.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/autoload.coffee deleted file mode 100644 index 2c14c3565..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/autoload.coffee +++ /dev/null @@ -1,58 +0,0 @@ -Caman.DOMUpdated = -> - imgs = document.querySelectorAll("img[data-caman]") - return unless imgs.length > 0 - - for img in imgs - parser = new CamanParser img, -> - @parse() - @execute() - -# If enabled, we check the page to see if there are any -# images with Caman instructions provided using HTML5 -# data attributes. -if Caman.autoload then do -> - if document.readyState is "complete" - Caman.DOMUpdated() - else - document.addEventListener "DOMContentLoaded", Caman.DOMUpdated, false - -# Parses Caman instructions embedded in the HTML data-caman attribute -class CamanParser - INST_REGEX = "(\\w+)\\((.*?)\\)" - - constructor: (ele, ready) -> - @dataStr = ele.getAttribute('data-caman') - @caman = Caman ele, ready.bind(@) - - parse: -> - @ele = @caman.canvas - - # First we find each instruction as a whole using a global - # regex search. - r = new RegExp(INST_REGEX, 'g') - unparsedInstructions = @dataStr.match r - return unless unparsedInstructions.length > 0 - - # Once we gather all the instructions, we go through each one - # and parse out the filter name + it's parameters. - r = new RegExp(INST_REGEX) - for inst in unparsedInstructions - [m, filter, args] = inst.match(r) - - # Create a factory function so we can catch any errors that - # are produced when running the filters. This also makes it very - # simple to support multiple/complex filter arguments. - instFunc = new Function("return function() { - this.#{filter}(#{args}); - };") - - try - func = instFunc() - func.call @caman - catch e - Log.debug e - - execute: -> - ele = @ele - @caman.render -> - ele.parentNode.replaceChild @toImage(), ele \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/blender.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/blender.coffee deleted file mode 100644 index 23eb3cde0..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/blender.coffee +++ /dev/null @@ -1,11 +0,0 @@ -# Built-in layer blenders. Many of these mimic Photoshop blend modes. -Caman.Blender = class Blender - @blenders = {} - - # Registers a blender. Can be used to add your own blenders outside of - # the core library, if needed. - @register: (name, func) -> @blenders[name] = func - - # Executes a blender to combine a layer with its parent. - @execute: (name, rgbaLayer, rgbaParent) -> - @blenders[name](rgbaLayer, rgbaParent) \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/calculate.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/calculate.coffee deleted file mode 100644 index fd883ec87..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/calculate.coffee +++ /dev/null @@ -1,87 +0,0 @@ -# Various math-heavy helpers -Caman.Calculate = class Calculate - # Calculates the distance between two points - @distance: (x1, y1, x2, y2) -> - Math.sqrt Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) - - # Generates a pseudorandom number that lies within the max - mix range. The number can be either - # an integer or a float depending on what the user specifies. - @randomRange: (min, max, getFloat = false) -> - rand = min + (Math.random() * (max - min)) - return if getFloat then rand.toFixed(getFloat) else Math.round(rand) - - # Calculates the luminance of a single pixel using a special weighted sum - @luminance: (rgba) -> (0.299 * rgba.r) + (0.587 * rgba.g) + (0.114 * rgba.b) - - # Generates a bezier curve given a start and end point, with two control points in between. - # Can also optionally bound the y values between a low and high bound. - # - # This is different than most bezier curve functions because it attempts to construct it in such - # a way that we can use it more like a simple input -> output system, or a one-to-one function. - # In other words we can provide an input color value, and immediately receive an output modified - # color value. - # - # Note that, by design, this does not force X values to be in the range [0..255]. This is to - # generalize the function a bit more. If you give it a starting X value that isn't 0, and/or a - # ending X value that isn't 255, you may run into problems with your filter! - @bezier: (start, ctrl1, ctrl2, end, lowBound, highBound) -> - x0 = start[0] - y0 = start[1] - x1 = ctrl1[0] - y1 = ctrl1[1] - x2 = ctrl2[0] - y2 = ctrl2[1] - x3 = end[0] - y3 = end[1] - bezier = {} - - # Calculate our X/Y coefficients - Cx = parseInt(3 * (x1 - x0), 10) - Bx = 3 * (x2 - x1) - Cx - Ax = x3 - x0 - Cx - Bx - - Cy = 3 * (y1 - y0) - By = 3 * (y2 - y1) - Cy - Ay = y3 - y0 - Cy - By - - # 1000 is actually arbitrary. We need to make sure we do enough - # calculations between 0 and 255 that, in even the more extreme - # circumstances, we calculate as many values as possible. In the event - # that an X value is skipped, it will be found later on using linear - # interpolation. - for i in [0...1000] - t = i / 1000 - - curveX = Math.round (Ax * Math.pow(t, 3)) + (Bx * Math.pow(t, 2)) + (Cx * t) + x0 - curveY = Math.round (Ay * Math.pow(t, 3)) + (By * Math.pow(t, 2)) + (Cy * t) + y0 - - if lowBound and curveY < lowBound - curveY = lowBound - else if highBound and curveY > highBound - curveY = highBound - - bezier[curveX] = curveY - - # Do a search for missing values in the bezier array and use linear - # interpolation to approximate their values - if bezier.length < end[0] + 1 - for i in [0..end[0]] - if not bezier[i]? - leftCoord = [i-1, bezier[i-1]] - - # Find the first value to the right. Ideally this loop will break - # very quickly. - for j in [i..end[0]] - if bezier[j]? - rightCoord = [j, bezier[j]] - break - - bezier[i] = leftCoord[1] + - ((rightCoord[1] - leftCoord[1]) / (rightCoord[0] - leftCoord[0])) * - (i - leftCoord[0]) - - # Edge case - bezier[end[0]] = bezier[end[0] - 1] if not bezier[end[0]]? - - return bezier - \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/caman.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/caman.coffee deleted file mode 100644 index 469ec70fa..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/caman.coffee +++ /dev/null @@ -1,545 +0,0 @@ -# NodeJS compatibility -if exports? - Root = exports - Canvas = require 'canvas' - Image = Canvas.Image - - Fiber = require 'fibers' - - fs = require 'fs' -else - Root = window - -# Here it begins. Caman is defined. -# There are many different initialization for Caman, which are described on the -# [Basic Usage](http://camanjs.com/docs) page. -# -# Initialization is tricky because we need to make sure everything we need is actually fully -# loaded in the DOM before proceeding. When initialized on an image, we need to make sure that the -# image is done loading before converting it to a canvas element and writing the pixel data. If we -# do this prematurely, the browser will throw a DOM Error, and chaos will ensue. In the event that -# we initialize Caman on a canvas element while specifying an image URL, we need to create a new -# image element, load the image, then continue with initialization. -# -# The main goal for Caman was simplicity, so all of this is handled transparently to the end-user. -Root.Caman = class Caman - @version: - release: "4.1.1" - date: "4/8/2013" - - # Debug mode enables console logging - @DEBUG: false - - # Are we in a NodeJS environment? - @NodeJS: exports? - - # Should we check the DOM for images with Caman instructions? - @autoload: not Caman.NodeJS - - # Allow reverting the canvas? - # If your JS process is running out of memory, disabling - # this could help drastically. - @allowRevert: true - - # Default cross-origin policy - @crossOrigin: "anonymous" - - @toString: -> - "Version " + Caman.version.release + ", Released " + Caman.version.date; - - # Set the URL of the image proxy script - @remoteProxy: "" - - # Change the GET param used with the proxy script if needed - @proxyParam: "camanProxyUrl" - - @getAttrId: (canvas) -> - return true if Caman.NodeJS - - if typeof canvas is "string" - canvas = $(canvas) - - return null unless canvas? and canvas.getAttribute? - canvas.getAttribute 'data-caman-id' - - constructor: -> - throw "Invalid arguments" if arguments.length is 0 - - if @ instanceof Caman - # We have to do this to avoid polluting the global scope - # because of how Coffeescript binds functions specified - # with => and the fact that Caman can be invoked as both - # a function and as a 'new' object. - @finishInit = @finishInit.bind(@) - @imageLoaded = @imageLoaded.bind(@) - - args = arguments[0] - - unless Caman.NodeJS - id = parseInt Caman.getAttrId(args[0]), 10 - callback = if typeof args[1] is "function" - args[1] - else if typeof args[2] is "function" - args[2] - else - -> - - if !isNaN(id) and Store.has(id) - return Store.execute(id, callback) - - # Every instance gets a unique ID. Makes it much simpler to check if two variables are the - # same instance. - @id = Util.uniqid.get() - - @initializedPixelData = @originalPixelData = null - @cropCoordinates = x: 0, y: 0 - @cropped = false - @resized = false - - @pixelStack = [] # Stores the pixel layers - @layerStack = [] # Stores all of the layers waiting to be rendered - @canvasQueue = [] # Stores all of the canvases to be processed - @currentLayer = null - @scaled = false - - @analyze = new Analyze @ - @renderer = new Renderer @ - - @domIsLoaded => - @parseArguments(args) - @setup() - - return @ - else - return new Caman(arguments) - - domIsLoaded: (cb) -> - if Caman.NodeJS - setTimeout => - cb.call(@) - , 0 - else - if document.readyState is "complete" - Log.debug "DOM initialized" - setTimeout => - cb.call(@) - , 0 - else - listener = => - if document.readyState is "complete" - Log.debug "DOM initialized" - cb.call(@) - - document.addEventListener "readystatechange", listener, false - - # All possible combinations: - # - # **1 argument** - # - Image selector - # - Image object - # - Canvas selector - # - Canvas object - # - # **2 arguments** - # - Image selector + callback - # - Image object + callback - # - Canvas selector + URL - # - Canvas object + URL - # - # **3 arguments** - # - Canvas selector + URL + callback - # - Canvas object + URL + callback - # - # **NodeJS** - # - file path - # - file object - # - file path + callback - # - file object + callback - parseArguments: (args) -> - throw "Invalid arguments given" if args.length is 0 - - # Defaults - @initObj = null - @initType = null - @imageUrl = null - @callback = -> - - # First argument is always our canvas/image - @setInitObject args[0] - return if args.length is 1 - - switch typeof args[1] - when "string" then @imageUrl = args[1] - when "function" then @callback = args[1] - - return if args.length is 2 - - @callback = args[2] - - if args.length is 4 - @options[key] = val for own key, val of args[4] - - setInitObject: (obj) -> - if Caman.NodeJS - @initObj = obj - @initType = 'node' - return - - if typeof obj is "object" - @initObj = obj - else - @initObj = $(obj) - - throw "Could not find image or canvas for initialization." unless @initObj? - - @initType = @initObj.nodeName.toLowerCase() - - setup: -> - switch @initType - when "node" then @initNode() - when "img" then @initImage() - when "canvas" then @initCanvas() - - initNode: -> - Log.debug "Initializing for NodeJS" - - @image = new Image() - @image.onload = => - Log.debug "Image loaded. Width = #{@imageWidth()}, Height = #{@imageHeight()}" - @canvas = new Canvas @imageWidth(), @imageHeight() - @finishInit() - - @image.onerror = (err) -> throw err - @image.src = @initObj - - initImage: -> - @image = @initObj - @canvas = document.createElement 'canvas' - @context = @canvas.getContext '2d' - Util.copyAttributes @image, @canvas, except: ['src'] - - @image.parentNode.replaceChild @canvas, @image - - @imageAdjustments() - @waitForImageLoaded() - - initCanvas: -> - @canvas = @initObj - @context = @canvas.getContext '2d' - - if @imageUrl? - @image = document.createElement 'img' - @image.src = @imageUrl - - @imageAdjustments() - @waitForImageLoaded() - else - @finishInit() - - imageAdjustments: -> - if @needsHiDPISwap() - Log.debug @image.src, "->", @hiDPIReplacement() - - @swapped = true - @image.src = @hiDPIReplacement() - - if IO.isRemote(@image) - @image.src = IO.proxyUrl(@image.src) - Log.debug "Remote image detected, using URL = #{@image.src}" - - waitForImageLoaded: -> - if @isImageLoaded() - @imageLoaded() - else - @image.onload = @imageLoaded - - isImageLoaded: -> - return false unless @image.complete - return false if @image.naturalWidth? and @image.naturalWidth is 0 - return true - - # Internet Explorer has issues figuring out image dimensions when they aren't - # explicitly defined apparently. We check the normal width/height properties first, - # but fall back to natural sizes if they are 0. - imageWidth: -> @image.width or @image.naturalWidth - imageHeight: -> @image.height or @image.naturalHeight - - imageLoaded: -> - Log.debug "Image loaded. Width = #{@imageWidth()}, Height = #{@imageHeight()}" - - if @swapped - @canvas.width = @imageWidth() / @hiDPIRatio() - @canvas.height = @imageHeight() / @hiDPIRatio() - else - @canvas.width = @imageWidth() - @canvas.height = @imageHeight() - - @finishInit() - - finishInit: -> - @context = @canvas.getContext '2d' unless @context? - - @originalWidth = @preScaledWidth = @width = @canvas.width - @originalHeight = @preScaledHeight = @height = @canvas.height - - @hiDPIAdjustments() - @assignId() unless @hasId() - - if @image? - @context.drawImage @image, - 0, 0, - @imageWidth(), @imageHeight(), - 0, 0, - @preScaledWidth, @preScaledHeight - - @reloadCanvasData() - - if Caman.allowRevert - @initializedPixelData = Util.dataArray(@pixelData.length) - @originalPixelData = Util.dataArray(@pixelData.length) - - for pixel, i in @pixelData - @initializedPixelData[i] = pixel - @originalPixelData[i] = pixel - - @dimensions = - width: @canvas.width - height: @canvas.height - - Store.put @id, @ - - @callback.call @,@ - - # Reset the callback so re-initialization doesn't - # trigger it again. - @callback = -> - - # If you have a separate context reference to this canvas outside of CamanJS - # and you make a change to the canvas outside of CamanJS, you will have to call - # this function to update our context reference to include those changes. - reloadCanvasData: -> - @imageData = @context.getImageData 0, 0, @canvas.width, @canvas.height - @pixelData = @imageData.data - - resetOriginalPixelData: -> - throw "Revert disabled" unless Caman.allowRevert - - @originalPixelData = Util.dataArray(@pixelData.length) - @originalPixelData.push pixel for pixel in @pixelData - - hasId: -> Caman.getAttrId(@canvas)? - - assignId: -> - return if Caman.NodeJS or @canvas.getAttribute 'data-caman-id' - @canvas.setAttribute 'data-caman-id', @id - - hiDPIDisabled: -> - @canvas.getAttribute('data-caman-hidpi-disabled') isnt null - - hiDPIAdjustments: -> - return if Caman.NodeJS or @hiDPIDisabled() - - ratio = @hiDPIRatio() - - if ratio isnt 1 - Log.debug "HiDPI ratio = #{ratio}" - @scaled = true - - @preScaledWidth = @canvas.width - @preScaledHeight = @canvas.height - - @canvas.width = @preScaledWidth * ratio - @canvas.height = @preScaledHeight * ratio - @canvas.style.width = "#{@preScaledWidth}px" - @canvas.style.height = "#{@preScaledHeight}px" - - @context.scale ratio, ratio - - @width = @originalWidth = @canvas.width - @height = @originalHeight = @canvas.height - - hiDPIRatio: -> - devicePixelRatio = window.devicePixelRatio or 1 - backingStoreRatio = @context.webkitBackingStorePixelRatio or - @context.mozBackingStorePixelRatio or - @context.msBackingStorePixelRatio or - @context.oBackingStorePixelRatio or - @context.backingStorePixelRatio or 1 - - devicePixelRatio / backingStoreRatio - - hiDPICapable: -> window.devicePixelRatio? and window.devicePixelRatio isnt 1 - - needsHiDPISwap: -> - return false if @hiDPIDisabled() or !@hiDPICapable() - @hiDPIReplacement() isnt null - - hiDPIReplacement: -> - return null unless @image? - @image.getAttribute 'data-caman-hidpi' - - replaceCanvas: (newCanvas) -> - oldCanvas = @canvas - @canvas = newCanvas - @context = @canvas.getContext '2d' - - oldCanvas.parentNode.replaceChild @canvas, oldCanvas - - @width = @canvas.width - @height = @canvas.height - - @reloadCanvasData() - - @dimensions = - width: @canvas.width - height: @canvas.height - - # Begins the rendering process - render: (callback = ->) -> - Event.trigger @, "renderStart" - - @renderer.execute => - @context.putImageData @imageData, 0, 0 - callback.call @ - - # Reverts the canvas back to it's original state while - # maintaining any cropped or resized dimensions. - revert: -> - throw "Revert disabled" unless Caman.allowRevert - - @pixelData[i] = pixel for pixel, i in @originalVisiblePixels() - @context.putImageData @imageData, 0, 0 - - # Completely resets the canvas back to it's original state. - # Any size adjustments will also be reset. - reset: -> - canvas = document.createElement('canvas') - Util.copyAttributes(@canvas, canvas) - - canvas.width = @originalWidth - canvas.height = @originalHeight - - ctx = canvas.getContext('2d') - imageData = ctx.getImageData 0, 0, canvas.width, canvas.height - pixelData = imageData.data - - pixelData[i] = pixel for pixel, i in @initializedPixelData - - ctx.putImageData imageData, 0, 0 - - @cropCoordinates = x: 0, y: 0 - @resized = false - - @replaceCanvas(canvas) - - # Returns the original pixel data while maintaining any - # cropping or resizing that may have occured. - originalVisiblePixels: -> - throw "Revert disabled" unless Caman.allowRevert - - pixels = [] - - startX = @cropCoordinates.x - endX = startX + @width - startY = @cropCoordinates.y - endY = startY + @height - - if @resized - canvas = document.createElement('canvas') - canvas.width = @originalWidth - canvas.height = @originalHeight - - ctx = canvas.getContext('2d') - imageData = ctx.getImageData 0, 0, canvas.width, canvas.height - pixelData = imageData.data - - pixelData[i] = pixel for pixel, i in @originalPixelData - - ctx.putImageData imageData, 0, 0 - - scaledCanvas = document.createElement('canvas') - scaledCanvas.width = @width - scaledCanvas.height = @height - - ctx = scaledCanvas.getContext('2d') - ctx.drawImage canvas, 0, 0, @originalWidth, @originalHeight, 0, 0, @width, @height - - pixelData = ctx.getImageData(0, 0, @width, @height).data - width = @width - else - pixelData = @originalPixelData - width = @originalWidth - - for i in [0...pixelData.length] by 4 - coord = PixelInfo.locationToCoordinates(i, width) - if (startX <= coord.x < endX) and (startY <= coord.y < endY) - pixels.push pixelData[i], - pixelData[i+1], - pixelData[i+2], - pixelData[i+3] - - pixels - - # Pushes the filter callback that modifies the RGBA object into the - # render queue - process: (name, processFn) -> - @renderer.add - type: Filter.Type.Single - name: name - processFn: processFn - - return @ - - # Pushes the kernel into the render queue - processKernel: (name, adjust, divisor, bias) -> - if not divisor - divisor = 0 - divisor += adjust[i] for i in [0...adjust.length] - - @renderer.add - type: Filter.Type.Kernel - name: name - adjust: adjust - divisor: divisor - bias: bias or 0 - - return @ - - # Adds a standalone plugin into the render queue - processPlugin: (plugin, args) -> - @renderer.add - type: Filter.Type.Plugin - plugin: plugin - args: args - - return @ - - # Pushes a new layer operation into the render queue and calls the layer - # callback - newLayer: (callback) -> - layer = new Layer @ - @canvasQueue.push layer - @renderer.add type: Filter.Type.LayerDequeue - - callback.call layer - - @renderer.add type: Filter.Type.LayerFinished - return @ - - # Pushes the layer context and moves to the next operation - executeLayer: (layer) -> @pushContext layer - - # Set all of the relevant data to the new layer - pushContext: (layer) -> - @layerStack.push @currentLayer - @pixelStack.push @pixelData - @currentLayer = layer - @pixelData = layer.pixelData - - # Restore the previous layer context - popContext: -> - @pixelData = @pixelStack.pop() - @currentLayer = @layerStack.pop() - - # Applies the current layer to its parent layer - applyCurrentLayer: -> @currentLayer.applyToParent() diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/convert.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/convert.coffee deleted file mode 100644 index 0c80a1ff0..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/convert.coffee +++ /dev/null @@ -1,351 +0,0 @@ -# Tons of color conversion functions -class Convert - # Converts the hex representation of a color to RGB values. - # Hex value can optionally start with the hash (#). - # - #
-  # @param   String  hex   The colors hex value
-  # @return  Array         The RGB representation
-  # 
- @hexToRGB: (hex) -> - hex = hex.substr(1) if hex.charAt(0) is "#" - r = parseInt hex.substr(0, 2), 16 - g = parseInt hex.substr(2, 2), 16 - b = parseInt hex.substr(4, 2), 16 - - r: r, g: g, b: b - - # Converts an RGB color to HSL. - # Assumes r, g, and b are in the set [0, 255] and - # returns h, s, and l in the set [0, 1]. - # - #
-  # @param   Number  r   Red channel
-  # @param   Number  g   Green channel
-  # @param   Number  b   Blue channel
-  # @return              The HSL representation
-  # 
- @rgbToHSL: (r, g, b) -> - if typeof r is "object" - g = r.g - b = r.b - r = r.r - - r /= 255 - g /= 255 - b /= 255 - - max = Math.max r, g, b - min = Math.min r, g, b - l = (max + min) / 2 - - if max is min - h = s = 0 - else - d = max - min - s = if l > 0.5 then d / (2 - max - min) else d / (max + min) - h = switch max - when r then (g - b) / d + (if g < b then 6 else 0) - when g then (b - r) / d + 2 - when b then (r - g) / d + 4 - - h /= 6 - - h: h, s: s, l: l - - # Converts an HSL color value to RGB. Conversion formula - # adapted from http://en.wikipedia.org/wiki/HSL_color_space. - # Assumes h, s, and l are contained in the set [0, 1] and - # returns r, g, and b in the set [0, 255]. - # - #
-  # @param   Number  h       The hue
-  # @param   Number  s       The saturation
-  # @param   Number  l       The lightness
-  # @return  Array           The RGB representation
-  # 
- @hslToRGB: (h, s, l) -> - if typeof h is "object" - s = h.s - l = h.l - h = h.h - - if s is 0 - r = g = b = l - else - q = if l < 0.5 then l * (1 + s) else l + s - l * s - p = 2 * l - q - - r = @hueToRGB p, q, h + 1/3 - g = @hueToRGB p, q, h - b = @hueToRGB p, q, h - 1/3 - - r: r * 255, g: g * 255, b: b * 255 - - # Converts from the hue color space back to RGB - @hueToRGB: (p, q, t) -> - if t < 0 then t += 1 - if t > 1 then t -= 1 - if t < 1/6 then return p + (q - p) * 6 * t - if t < 1/2 then return q - if t < 2/3 then return p + (q - p) * (2/3 - t) * 6 - return p - - # Converts an RGB color value to HSV. Conversion formula - # adapted from http://en.wikipedia.org/wiki/HSV_color_space. - # Assumes r, g, and b are contained in the set [0, 255] and - # returns h, s, and v in the set [0, 1]. - # - #
-  # @param   Number  r       The red color value
-  # @param   Number  g       The green color value
-  # @param   Number  b       The blue color value
-  # @return  Array           The HSV representation
-  # 
- @rgbToHSV: (r, g, b) -> - r /= 255 - g /= 255 - b /= 255 - - max = Math.max r, g, b - min = Math.min r, g, b - v = max - d = max - min - - s = if max is 0 then 0 else d / max - - if max is min - h = 0 - else - h = switch max - when r then (g - b) / d + (if g < b then 6 else 0) - when g then (b - r) / d + 2 - when b then (r - g) / d + 4 - - h /= 6 - - h: h, s: s, v: v - - # Converts an HSV color value to RGB. Conversion formula - # adapted from http://en.wikipedia.org/wiki/HSV_color_space. - # Assumes h, s, and v are contained in the set [0, 1] and - # returns r, g, and b in the set [0, 255]. - # - #
-  # @param   Number  h       The hue
-  # @param   Number  s       The saturation
-  # @param   Number  v       The value
-  # @return  Array           The RGB representation
-  # 
- @hsvToRGB: (h, s, v) -> - i = Math.floor h * 6 - f = h * 6 - i - p = v * (1 - s) - q = v * (1 - f * s) - t = v * (1 - (1 - f) * s) - - switch i % 6 - when 0 - r = v - g = t - b = p - when 1 - r = q - g = v - b = p - when 2 - r = p - g = v - b = t - when 3 - r = p - g = q - b = v - when 4 - r = t - g = p - b = v - when 5 - r = v - g = p - b = q - - r: r * 255, g: g * 255, b: b * 255 - - # Converts a RGB color value to the XYZ color space. Formulas - # are based on http://en.wikipedia.org/wiki/SRGB assuming that - # RGB values are sRGB. - # - # Assumes r, g, and b are contained in the set [0, 255] and - # returns x, y, and z. - # - #
-  # @param   Number  r       The red color value
-  # @param   Number  g       The green color value
-  # @param   Number  b       The blue color value
-  # @return  Array           The XYZ representation
-  # 
- @rgbToXYZ: (r, g, b) -> - r /= 255 - g /= 255 - b /= 255 - - if r > 0.04045 - r = Math.pow((r + 0.055) / 1.055, 2.4) - else - r /= 12.92 - - if g > 0.04045 - g = Math.pow((g + 0.055) / 1.055, 2.4) - else - g /= 12.92 - - if b > 0.04045 - b = Math.pow((b + 0.055) / 1.055, 2.4) - else - b /= 12.92 - - x = r * 0.4124 + g * 0.3576 + b * 0.1805; - y = r * 0.2126 + g * 0.7152 + b * 0.0722; - z = r * 0.0193 + g * 0.1192 + b * 0.9505; - - x: x * 100, y: y * 100, z: z * 100 - - # Converts a XYZ color value to the sRGB color space. Formulas - # are based on http://en.wikipedia.org/wiki/SRGB and the resulting - # RGB value will be in the sRGB color space. - # Assumes x, y and z values are whatever they are and returns - # r, g and b in the set [0, 255]. - # - #
-  # @param   Number  x       The X value
-  # @param   Number  y       The Y value
-  # @param   Number  z       The Z value
-  # @return  Array           The RGB representation
-  # 
- @xyzToRGB: (x, y, z) -> - x /= 100 - y /= 100 - z /= 100 - - r = (3.2406 * x) + (-1.5372 * y) + (-0.4986 * z) - g = (-0.9689 * x) + (1.8758 * y) + (0.0415 * z) - b = (0.0557 * x) + (-0.2040 * y) + (1.0570 * z) - - if r > 0.0031308 - r = (1.055 * Math.pow(r, 0.4166666667)) - 0.055 - else - r *= 12.92 - - if g > 0.0031308 - g = (1.055 * Math.pow(g, 0.4166666667)) - 0.055 - else - g *= 12.92 - - if b > 0.0031308 - b = (1.055 * Math.pow(b, 0.4166666667)) - 0.055 - else - b *= 12.92 - - r: r * 255, g: g * 255, b: b * 255 - - # Converts a XYZ color value to the CIELAB color space. Formulas - # are based on http://en.wikipedia.org/wiki/Lab_color_space - # The reference white point used in the conversion is D65. - # Assumes x, y and z values are whatever they are and returns - # L*, a* and b* values - # - #
-  # @param   Number  x       The X value
-  # @param   Number  y       The Y value
-  # @param   Number  z       The Z value
-  # @return  Array           The Lab representation
-  # 
- @xyzToLab: (x, y, z) -> - if typeof x is "object" - y = x.y - z = x.z - x = x.x - - whiteX = 95.047 - whiteY = 100.0 - whiteZ = 108.883 - - x /= whiteX - y /= whiteY - z /= whiteZ - - if x > 0.008856451679 - x = Math.pow(x, 0.3333333333) - else - x = (7.787037037 * x) + 0.1379310345 - - if y > 0.008856451679 - y = Math.pow(y, 0.3333333333) - else - y = (7.787037037 * y) + 0.1379310345 - - if z > 0.008856451679 - z = Math.pow(z, 0.3333333333) - else - z = (7.787037037 * z) + 0.1379310345 - - l = 116 * y - 16 - a = 500 * (x - y) - b = 200 * (y - z) - - l: l, a: a, b: b - - # Converts a L*, a*, b* color values from the CIELAB color space - # to the XYZ color space. Formulas are based on - # http://en.wikipedia.org/wiki/Lab_color_space - # - # The reference white point used in the conversion is D65. - # Assumes L*, a* and b* values are whatever they are and returns - # x, y and z values. - # - #
-  # @param   Number  l       The L* value
-  # @param   Number  a       The a* value
-  # @param   Number  b       The b* value
-  # @return  Array           The XYZ representation
-  # 
- @labToXYZ: (l, a, b) -> - if typeof l is "object" - a = l.a - b = l.b - l = l.l - - y = (l + 16) / 116 - x = y + (a / 500) - z = y - (b / 200) - - if x > 0.2068965517 - x = x * x * x - else - x = 0.1284185493 * (x - 0.1379310345) - - if y > 0.2068965517 - y = y * y * y - else - y = 0.1284185493 * (y - 0.1379310345) - - if z > 0.2068965517 - z = z * z * z - else - z = 0.1284185493 * (z - 0.1379310345) - - # D65 reference white point - x: x * 95.047, y: y * 100.0, z: z * 108.883 - - @rgbToLab: (r, g, b) -> - if typeof r is "object" - g = r.g - b = r.b - r = r.r - - xyz = @rgbToXYZ(r, g, b) - @xyzToLab xyz - - @labToRGB: (l, a, b) -> - \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/event.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/event.coffee deleted file mode 100644 index 4214cba26..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/event.coffee +++ /dev/null @@ -1,43 +0,0 @@ -# Event system that can be used to register callbacks that get fired -# during certain times in the render process. -class Event - @events = {} - - # All of the supported event types - @types = [ - "processStart" - "processComplete" - "renderStart" - "renderFinished" - "blockStarted" - "blockFinished" - ] - - # Trigger an event - @trigger: (target, type, data) -> - if @events[type] and @events[type].length - for event in @events[type] - if event.target is null or target.id is event.target.id - event.fn.call target, data - - # Listen for an event. Optionally bind the listen to a single CamanInstance - # or all CamanInstances. - @listen: (target, type, fn) -> - # Adjust arguments if target is omitted - if typeof target is "string" - _type = target - _fn = type - - target = null - type = _type - fn = _fn - - # Validation - return false if type not in @types - - @events[type] = [] if not @events[type] - @events[type].push target: target, fn: fn - - return true - -Caman.Event = Event \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/filter.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/filter.coffee deleted file mode 100644 index 0c0b408c7..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/filter.coffee +++ /dev/null @@ -1,13 +0,0 @@ -# Responsible for storing all of the filters -Caman.Filter = class Filter - # All of the different render operatives - @Type = - Single: 1 - Kernel: 2 - LayerDequeue: 3 - LayerFinished: 4 - LoadOverlay: 5 - Plugin: 6 - - # Registers a filter function - @register: (name, filterFunc) -> Caman::[name] = filterFunc \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/io.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/io.coffee deleted file mode 100644 index 483e72a31..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/io.coffee +++ /dev/null @@ -1,90 +0,0 @@ -# Various I/O based operations -Caman.IO = class IO - @domainRegex = /(?:(?:http|https):\/\/)((?:\w+)\.(?:(?:\w|\.)+))/ - - # Is the given URL remote? - # If a cross-origin setting is set, we assume you have CORS - # properly configured. - @isRemote: (img) -> - return false unless img? - return false if @corsEnabled(img) - return @isURLRemote img.src - - @corsEnabled: (img) -> - img.crossOrigin? and img.crossOrigin.toLowerCase() in ['anonymous', 'use-credentials'] - - @isURLRemote: (url) -> - matches = url.match @domainRegex - return if matches then matches[1] isnt document.domain else false - - @remoteCheck: (src) -> - if @isURLRemote src - if not Caman.remoteProxy.length - Log.info "Attempting to load a remote image without a configured proxy. URL: #{src}" - return - else - if Caman.isURLRemote Caman.remoteProxy - Log.info "Cannot use a remote proxy for loading images." - return - - "#{Caman.remoteProxy}?camanProxyUrl=#{encodeURIComponent(src)}" - - - @proxyUrl: (src) -> - "#{Caman.remoteProxy}?#{Caman.proxyParam}=#{encodeURIComponent(src)}" - - # Shortcut for using one of the bundled proxies. - @useProxy: (lang) -> - langToExt = - ruby: 'rb' - python: 'py' - perl: 'pl' - javascript: 'js' - - lang = lang.toLowerCase() - lang = langToExt[lang] if langToExt[lang]? - "proxies/caman_proxy.#{lang}" - -# Grabs the canvas data, encodes it to Base64, then sets the browser location to -# the encoded data so that the user will be prompted to download it. -Caman::save = -> - if exports? - @nodeSave.apply @, arguments - else - @browserSave.apply @, arguments - -Caman::browserSave = (type = "png") -> - type = type.toLowerCase() - - # Force download (its a bit hackish) - image = @toBase64(type).replace "image/#{type}", "image/octet-stream" - document.location.href = image - -Caman::nodeSave = (file, overwrite = true) -> - try - stats = fs.statSync file - return false if stats.isFile() and not overwrite - catch e - Log.debug "Creating output file #{file}" - - fs.writeFile file, @canvas.toBuffer(), -> - Log.debug "Finished writing to #{file}" - -# Takes the current canvas data, converts it to Base64, then sets it as the source -# of a new Image object and returns it. -Caman::toImage = (type) -> - img = document.createElement 'img' - img.src = @toBase64 type - img.width = @dimensions.width - img.height = @dimensions.height - - if window.devicePixelRatio - img.width /= window.devicePixelRatio - img.height /= window.devicePixelRatio - - return img - -# Base64 encodes the current canvas -Caman::toBase64 = (type = "png") -> - type = type.toLowerCase() - return @canvas.toDataURL "image/#{type}" diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/layer.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/layer.coffee deleted file mode 100644 index 40c43e5f4..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/layer.coffee +++ /dev/null @@ -1,116 +0,0 @@ -# The entire layering system for Caman resides in this file. Layers get their own canvasLayer -# objectwhich is created when newLayer() is called. For extensive information regarding the -# specifics of howthe layering system works, there is an in-depth blog post on this very topic. -# Instead of copying the entirety of that post, I'll simply point you towards the -# [blog link](http://blog.meltingice.net/programming/implementing-layers-camanjs). -# -# However, the gist of the layering system is that, for each layer, it creates a new canvas -# element and then either copies the parent layer's data or applies a solid color to the new -# layer. After some (optional) effects are applied, the layer is blended back into the parent -# canvas layer using one of many different blending algorithms. -# -# You can also load an image (local or remote, with a proxy) into a canvas layer, which is useful -# if you want to add textures to an image. -class Layer - constructor: (@c) -> - # Compatibility - @filter = @c - - @options = - blendingMode: 'normal' - opacity: 1.0 - - # Each layer gets its own unique ID - @layerID = Util.uniqid.get() - - # Create the canvas for this layer - @canvas = if exports? then new Canvas() else document.createElement('canvas') - - @canvas.width = @c.dimensions.width - @canvas.height = @c.dimensions.height - - @context = @canvas.getContext('2d') - @context.createImageData @canvas.width, @canvas.height - @imageData = @context.getImageData 0, 0, @canvas.width, @canvas.height - @pixelData = @imageData.data - - # If you want to create nested layers - newLayer: (cb) -> @c.newLayer.call @c, cb - - # Sets the blending mode of this layer. The mode is the name of a blender function. - setBlendingMode: (mode) -> - @options.blendingMode = mode - return @ - - # Sets the opacity of this layer. This affects how much of this layer is applied to the parent - # layer at render time. - opacity: (opacity) -> - @options.opacity = opacity / 100 - return @ - - # Copies the contents of the parent layer to this layer - copyParent: -> - parentData = @c.pixelData - - for i in [0...@c.pixelData.length] by 4 - @pixelData[i] = parentData[i] - @pixelData[i+1] = parentData[i+1] - @pixelData[i+2] = parentData[i+2] - @pixelData[i+3] = parentData[i+3] - - return @ - - # Fills this layer with a single color - fillColor: -> @c.fillColor.apply @c, arguments - - # Loads and overlays an image onto this layer - overlayImage: (image) -> - if typeof image is "object" - image = image.src - else if typeof image is "string" and image[0] is "#" - image = $(image).src - - return @ if not image - - @c.renderer.renderQueue.push - type: Filter.Type.LoadOverlay - src: image - layer: @ - - return @ - - # Takes the contents of this layer and applies them to the parent layer at render time. This - # should never be called explicitly by the user. - applyToParent: -> - parentData = @c.pixelStack[@c.pixelStack.length - 1] - layerData = @c.pixelData - - for i in [0...layerData.length] by 4 - rgbaParent = - r: parentData[i] - g: parentData[i+1] - b: parentData[i+2] - a: parentData[i+3] - - rgbaLayer = - r: layerData[i] - g: layerData[i+1] - b: layerData[i+2] - a: layerData[i+3] - - result = Blender.execute @options.blendingMode, rgbaLayer, rgbaParent - - result.r = Util.clampRGB result.r - result.g = Util.clampRGB result.g - result.b = Util.clampRGB result.b - result.a = rgbaLayer.a if not result.a? - - parentData[i] = rgbaParent.r - ( - (rgbaParent.r - result.r) * (@options.opacity * (result.a / 255)) - ) - parentData[i+1] = rgbaParent.g - ( - (rgbaParent.g - result.g) * (@options.opacity * (result.a / 255)) - ) - parentData[i+2] = rgbaParent.b - ( - (rgbaParent.b - result.b) * (@options.opacity * (result.a / 255)) - ) diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/logger.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/logger.coffee deleted file mode 100644 index 75ae67225..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/logger.coffee +++ /dev/null @@ -1,16 +0,0 @@ -# Simple console logger class that can be toggled on and off based on Caman.DEBUG -class Logger - constructor: -> - for name in ['log', 'info', 'warn', 'error'] - @[name] = do (name) -> - (args...) -> - return if not Caman.DEBUG - try - console[name].apply console, args - catch e - # We're probably using IE9 or earlier - console[name] args - - @debug = @log - -Log = new Logger() \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/pixelinfo.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/pixelinfo.coffee deleted file mode 100644 index 96108df6c..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/pixelinfo.coffee +++ /dev/null @@ -1,73 +0,0 @@ -# This object is available inside of the process() loop, and it lets filter developers have simple -# access to any arbitrary pixel in the image, as well as information about the current pixel in -# the loop. -class PixelInfo - @coordinatesToLocation: (x, y, width) -> - (y * width + x) * 4 - - @locationToCoordinates: (loc, width) -> - y = Math.floor(loc / (width * 4)) - x = (loc % (width * 4)) / 4 - - return x: x, y: y - - constructor: (@c) -> @loc = 0 - - # Retrieves the X, Y location of the current pixel. The origin is at the bottom left corner of - # the image, like a normal coordinate system. - locationXY: -> - y = @c.dimensions.height - Math.floor(@loc / (@c.dimensions.width * 4)) - x = (@loc % (@c.dimensions.width * 4)) / 4 - - return x: x, y: y - - # Returns an RGBA object for a pixel whose location is specified in relation to the current - # pixel. - getPixelRelative: (horiz, vert) -> - # We invert the vert_offset in order to make the coordinate system non-inverted. In laymans - # terms: -1 means down and +1 means up. - newLoc = @loc + (@c.dimensions.width * 4 * (vert * -1)) + (4 * horiz) - - if newLoc > @c.pixelData.length or newLoc < 0 - return r: 0, g: 0, b: 0, a: 0 - - return { - r: @c.pixelData[newLoc] - g: @c.pixelData[newLoc + 1] - b: @c.pixelData[newLoc + 2] - a: @c.pixelData[newLoc + 3] - } - - # The counterpart to getPixelRelative, this updates the value of a pixel whose location is - # specified in relation to the current pixel. - putPixelRelative: (horiz, vert, rgba) -> - nowLoc = @loc + (@c.dimensions.width * 4 * (vert * -1)) + (4 * horiz) - - return if newLoc > @c.pixelData.length or newLoc < 0 - - @c.pixelData[newLoc] = rgba.r - @c.pixelData[newLoc + 1] = rgba.g - @c.pixelData[newLoc + 2] = rgba.b - @c.pixelData[newLoc + 3] = rgba.a - - return true - - # Gets an RGBA object for an arbitrary pixel in the canvas specified by absolute X, Y coordinates - getPixel: (x, y) -> - loc = @coordinatesToLocation(x, y, @width) - - return { - r: @c.pixelData[loc] - g: @c.pixelData[loc + 1] - b: @c.pixelData[loc + 2] - a: @c.pixelData[loc + 3] - } - - # Updates the pixel at the given X, Y coordinate - putPixel: (x, y, rgba) -> - loc = @coordinatesToLocation(x, y, @width) - - @c.pixelData[loc] = rgba.r - @c.pixelData[loc + 1] = rgba.g - @c.pixelData[loc + 2] = rgba.b - @c.pixelData[loc + 3] = rgba.a diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/plugin.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/plugin.coffee deleted file mode 100644 index 30fdcc00f..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/plugin.coffee +++ /dev/null @@ -1,8 +0,0 @@ -# Stores and registers standalone plugins -class Plugin - @plugins = {} - - @register: (name, plugin) -> @plugins[name] = plugin - @execute: (context, name, args) -> @plugins[name].apply context, args - -Caman.Plugin = Plugin \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/renderer.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/renderer.coffee deleted file mode 100644 index 614ea9c97..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/renderer.coffee +++ /dev/null @@ -1,219 +0,0 @@ -# Handles all of the various rendering methods in Caman. Most of the image modification happens -# here. A new Renderer object is created for every render operation. -Caman.Renderer = class Renderer - # The number of blocks to split the image into during the render process to simulate - # concurrency. This also helps the browser manage the (possibly) long running render jobs. - @Blocks = if Caman.NodeJS then require('os').cpus().length else 4 - - constructor: (@c) -> - @renderQueue = [] - @modPixelData = null - - add: (job) -> - return unless job? - @renderQueue.push job - - # Grabs the next operation from the render queue and passes it to Renderer - # for execution - processNext: => - # If the queue is empty, fire the finished callback - if @renderQueue.length is 0 - Event.trigger @, "renderFinished" - @finishedFn.call(@c) if @finishedFn? - - return @ - - @currentJob = @renderQueue.shift() - - switch @currentJob.type - when Filter.Type.LayerDequeue - layer = @c.canvasQueue.shift() - @c.executeLayer layer - @processNext() - when Filter.Type.LayerFinished - @c.applyCurrentLayer() - @c.popContext() - @processNext() - when Filter.Type.LoadOverlay - @loadOverlay @currentJob.layer, @currentJob.src - when Filter.Type.Plugin - @executePlugin() - else - @executeFilter() - - execute: (callback) -> - @finishedFn = callback - @modPixelData = Util.dataArray(@c.pixelData.length) - - @processNext() - - eachBlock: (fn) -> - # Prepare all the required render data - @blocksDone = 0 - - n = @c.pixelData.length - blockPixelLength = Math.floor (n / 4) / Renderer.Blocks - blockN = blockPixelLength * 4 - lastBlockN = blockN + ((n / 4) % Renderer.Blocks) * 4 - - for i in [0...Renderer.Blocks] - start = i * blockN - end = start + (if i is Renderer.Blocks - 1 then lastBlockN else blockN) - - if Caman.NodeJS - f = Fiber => fn.call(@, i, start, end) - bnum = f.run() - @blockFinished(bnum) - else - setTimeout do (i, start, end) => - => fn.call(@, i, start, end) - , 0 - - # The core of the image rendering, this function executes the provided filter. - # - # NOTE: this does not write the updated pixel data to the canvas. That happens when all filters - # are finished rendering in order to be as fast as possible. - executeFilter: -> - Event.trigger @c, "processStart", @currentJob - - if @currentJob.type is Filter.Type.Single - @eachBlock @renderBlock - else - @eachBlock @renderKernel - - # Executes a standalone plugin - executePlugin: -> - Log.debug "Executing plugin #{@currentJob.plugin}" - Plugin.execute @c, @currentJob.plugin, @currentJob.args - Log.debug "Plugin #{@currentJob.plugin} finished!" - - @processNext() - - # Renders a single block of the canvas with the current filter function - renderBlock: (bnum, start, end) -> - Log.debug "Block ##{bnum} - Filter: #{@currentJob.name}, Start: #{start}, End: #{end}" - Event.trigger @c, "blockStarted", - blockNum: bnum - totalBlocks: Renderer.Blocks - startPixel: start - endPixel: end - - data = r: 0, g: 0, b: 0, a: 0 - pixelInfo = new PixelInfo @c - - for i in [start...end] by 4 - pixelInfo.loc = i - - data.r = @c.pixelData[i] - data.g = @c.pixelData[i+1] - data.b = @c.pixelData[i+2] - data.a = @c.pixelData[i+3] - - res = @currentJob.processFn.call pixelInfo, data - res.a = data.a if not res.a? - - @c.pixelData[i] = Util.clampRGB res.r - @c.pixelData[i+1] = Util.clampRGB res.g - @c.pixelData[i+2] = Util.clampRGB res.b - @c.pixelData[i+3] = Util.clampRGB res.a - - if Caman.NodeJS - Fiber.yield(bnum) - else - @blockFinished bnum - - # Applies an image kernel to the canvas - renderKernel: (bnum, start, end) -> - name = @currentJob.name - bias = @currentJob.bias - divisor = @currentJob.divisor - n = @c.pixelData.length - - adjust = @currentJob.adjust - adjustSize = Math.sqrt adjust.length - - kernel = [] - - Log.debug "Rendering kernel - Filter: #{@currentJob.name}" - - start = Math.max start, @c.dimensions.width * 4 * ((adjustSize - 1) / 2) - end = Math.min end, n - (@c.dimensions.width * 4 * ((adjustSize - 1) / 2)) - - builder = (adjustSize - 1) / 2 - - pixelInfo = new PixelInfo @c - - for i in [start...end] by 4 - pixelInfo.loc = i - builderIndex = 0 - - for j in [-builder..builder] - for k in [builder..-builder] - pixel = pixelInfo.getPixelRelative j, k - kernel[builderIndex * 3] = pixel.r - kernel[builderIndex * 3 + 1] = pixel.g - kernel[builderIndex * 3 + 2] = pixel.b - - builderIndex++ - - res = @processKernel adjust, kernel, divisor, bias - - @modPixelData[i] = Util.clampRGB(res.r) - @modPixelData[i+1] = Util.clampRGB(res.g) - @modPixelData[i+2] = Util.clampRGB(res.b) - @modPixelData[i+3] = @c.pixelData[i+3] - - if Caman.NodeJS - Fiber.yield(bnum) - else - @blockFinished bnum - - # Called when a single block is finished rendering. Once all blocks are done, we signal that this - # filter is finished rendering and continue to the next step. - blockFinished: (bnum) -> - Log.debug "Block ##{bnum} finished! Filter: #{@currentJob.name}" if bnum >= 0 - @blocksDone++ - - Event.trigger @c, "blockFinished", - blockNum: bnum - blocksFinished: @blocksDone - totalBlocks: Renderer.Blocks - - if @blocksDone is Renderer.Blocks - if @currentJob.type is Filter.Type.Kernel - for i in [0...@c.pixelData.length] - @c.pixelData[i] = @modPixelData[i] - - Log.debug "Filter #{@currentJob.name} finished!" if bnum >=0 - Event.trigger @c, "processComplete", @currentJob - - @processNext() - - # The "filter function" for kernel adjustments. - processKernel: (adjust, kernel, divisor, bias) -> - val = r: 0, g: 0, b: 0 - - for i in [0...adjust.length] - val.r += adjust[i] * kernel[i * 3] - val.g += adjust[i] * kernel[i * 3 + 1] - val.b += adjust[i] * kernel[i * 3 + 2] - - val.r = (val.r / divisor) + bias - val.g = (val.g / divisor) + bias - val.b = (val.b / divisor) + bias - val - - # Loads an image onto the current canvas - loadOverlay: (layer, src) -> - img = document.createElement 'img' - img.onload = => - layer.context.drawImage img, 0, 0, @c.dimensions.width, @c.dimensions.height - layer.imageData = layer.context.getImageData 0, 0, @c.dimensions.width, @c.dimensions.height - layer.pixelData = layer.imageData.data - - @c.pixelData = layer.pixelData - - @processNext() - - proxyUrl = IO.remoteCheck src - img.src = if proxyUrl? then proxyUrl else src \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/store.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/store.coffee deleted file mode 100644 index ed7f1b722..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/store.coffee +++ /dev/null @@ -1,17 +0,0 @@ -# Used for storing instances of CamanInstance objects such that, when Caman() is called on an -# already initialized element, it returns that object instead of re-initializing. -Caman.Store = class Store - @items = {} - - @has: (search) -> @items[search]? - @get: (search) -> @items[search] - @put: (name, obj) -> @items[name] = obj - @execute: (search, callback) -> - setTimeout => - callback.call @get(search), @get(search) - , 0 - - return @get(search) - - @flush: (name = false) -> - if name then delete @items[name] else @items = {} \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/core/util.coffee b/mig/images/lib/CamanJS-4.1.1/src/core/util.coffee deleted file mode 100644 index 38d0ce251..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/core/util.coffee +++ /dev/null @@ -1,42 +0,0 @@ -# Look what you make me do Javascript -slice = Array::slice - -# DOM simplifier (no jQuery dependency) -# NodeJS compatible -$ = (sel, root = document) -> - return sel if typeof sel is "object" or exports? - root.querySelector sel - -class Util - # Unique value utility - @uniqid = do -> - id = 0 - get: -> id++ - - # Helper function that extends one object with all the properies of other objects - @extend = (obj) -> - dest = obj - src = slice.call arguments, 1 - - for copy in src - for own prop of copy - dest[prop] = copy[prop] - - return dest - - # In order to stay true to the latest spec, RGB values must be clamped between - # 0 and 255. If we don't do this, weird things happen. - @clampRGB = (val) -> - return 0 if val < 0 - return 255 if val > 255 - val - - @copyAttributes: (from, to, opts={}) -> - for attr in from.attributes - continue if opts.except? and attr.nodeName in opts.except - to.setAttribute(attr.nodeName, attr.nodeValue) - - # Support for browsers that don't know Uint8Array (such as IE9) - @dataArray: (length = 0) -> - return new Uint8Array(length) if Caman.NodeJS or window.Uint8Array? - return new Array(length) \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/lib/blenders.coffee b/mig/images/lib/CamanJS-4.1.1/src/lib/blenders.coffee deleted file mode 100644 index 452755655..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/lib/blenders.coffee +++ /dev/null @@ -1,81 +0,0 @@ -# Directly apply the child layer's pixels to the parent layer with no special changes -Blender.register "normal", (rgbaLayer, rgbaParent) -> - r: rgbaLayer.r - g: rgbaLayer.g - b: rgbaLayer.b - -# Apply the child to the parent by multiplying the color values. This generally creates contrast. -Blender.register "multiply", (rgbaLayer, rgbaParent) -> - r: (rgbaLayer.r * rgbaParent.r) / 255 - g: (rgbaLayer.g * rgbaParent.g) / 255 - b: (rgbaLayer.b * rgbaParent.b) / 255 - -Blender.register "screen", (rgbaLayer, rgbaParent) -> - r: 255 - (((255 - rgbaLayer.r) * (255 - rgbaParent.r)) / 255) - g: 255 - (((255 - rgbaLayer.g) * (255 - rgbaParent.g)) / 255) - b: 255 - (((255 - rgbaLayer.b) * (255 - rgbaParent.b)) / 255) - - -Blender.register "overlay", (rgbaLayer, rgbaParent) -> - result = {} - result.r = - if rgbaParent.r > 128 - 255 - 2 * (255 - rgbaLayer.r) * (255 - rgbaParent.r) / 255 - else (rgbaParent.r * rgbaLayer.r * 2) / 255 - - result.g = - if rgbaParent.g > 128 - 255 - 2 * (255 - rgbaLayer.g) * (255 - rgbaParent.g) / 255 - else (rgbaParent.g * rgbaLayer.g * 2) / 255 - - result.b = - if rgbaParent.b > 128 - 255 - 2 * (255 - rgbaLayer.b) * (255 - rgbaParent.b) / 255 - else (rgbaParent.b * rgbaLayer.b * 2) / 255 - - result - -Blender.register "difference", (rgbaLayer, rgbaParent) -> - r: rgbaLayer.r - rgbaParent.r - g: rgbaLayer.g - rgbaParent.g - b: rgbaLayer.b - rgbaParent.b - -Blender.register "addition", (rgbaLayer, rgbaParent) -> - r: rgbaParent.r + rgbaLayer.r - g: rgbaParent.g + rgbaLayer.g - b: rgbaParent.b + rgbaLayer.b - -Blender.register "exclusion", (rgbaLayer, rgbaParent) -> - r: 128 - 2 * (rgbaParent.r - 128) * (rgbaLayer.r - 128) / 255 - g: 128 - 2 * (rgbaParent.g - 128) * (rgbaLayer.g - 128) / 255 - b: 128 - 2 * (rgbaParent.b - 128) * (rgbaLayer.b - 128) / 255 - -Blender.register "softLight", (rgbaLayer, rgbaParent) -> - result = {} - - result.r = - if rgbaParent.r > 128 - 255 - ((255 - rgbaParent.r) * (255 - (rgbaLayer.r - 128))) / 255 - else (rgbaParent.r * (rgbaLayer.r + 128)) / 255 - - result.g = - if rgbaParent.g > 128 - 255 - ((255 - rgbaParent.g) * (255 - (rgbaLayer.g - 128))) / 255 - else (rgbaParent.g * (rgbaLayer.g + 128)) / 255 - - result.b = - if rgbaParent.b > 128 - 255 - ((255 - rgbaParent.b) * (255 - (rgbaLayer.b - 128))) / 255 - else (rgbaParent.b * (rgbaLayer.b + 128)) / 255 - - result - -Blender.register "lighten", (rgbaLayer, rgbaParent) -> - r: if rgbaParent.r > rgbaLayer.r then rgbaParent.r else rgbaLayer.r - g: if rgbaParent.g > rgbaLayer.g then rgbaParent.g else rgbaLayer.g - b: if rgbaParent.b > rgbaLayer.b then rgbaParent.b else rgbaLayer.b - -Blender.register "darken", (rgbaLayer, rgbaParent) -> - r: if rgbaParent.r > rgbaLayer.r then rgbaLayer.r else rgbaParent.r - g: if rgbaParent.g > rgbaLayer.g then rgbaLayer.g else rgbaParent.g - b: if rgbaParent.b > rgbaLayer.b then rgbaLayer.b else rgbaParent.b \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/lib/filters.coffee b/mig/images/lib/CamanJS-4.1.1/src/lib/filters.coffee deleted file mode 100644 index c62cde4bb..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/lib/filters.coffee +++ /dev/null @@ -1,373 +0,0 @@ -# The filters define all of the built-in functionality that comes with Caman (as opposed to being -# provided by a plugin). All of these filters are ratherbasic, but are extremely powerful when -# many are combined. For information on creating plugins, check out the -# [Plugin Creation](http://camanjs.com/docs/plugin-creation) page, and for information on using -# the plugins, check out the [Built-In Functionality](http://camanjs.com/docs/built-in) page. - -# ## Fill Color -# Fills the canvas with a single solid color. -# -# ### Arguments -# Can take either separate R, G, and B values as arguments, or a single hex color value. -Filter.register "fillColor", -> - if arguments.length is 1 - color = Convert.hexToRGB arguments[0] - else - color = - r: arguments[0] - g: arguments[1] - b: arguments[2] - - @process "fillColor", (rgba) -> - rgba.r = color.r - rgba.g = color.g - rgba.b = color.b - rgba.a = 255 - rgba - -# ## Brightness -# Simple brightness adjustment -# -# ### Arguments -# Range is -100 to 100. Values < 0 will darken image while values > 0 will brighten. -Filter.register "brightness", (adjust) -> - adjust = Math.floor 255 * (adjust / 100) - - @process "brightness", (rgba) -> - rgba.r += adjust - rgba.g += adjust - rgba.b += adjust - rgba - -# ## Saturation -# Adjusts the color saturation of the image. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will desaturate the image while values > 0 will saturate it. -# **If you want to completely desaturate the image**, using the greyscale filter is highly -# recommended because it will yield better results. -Filter.register "saturation", (adjust) -> - adjust *= -0.01 - - @process "saturation", (rgba) -> - max = Math.max rgba.r, rgba.g, rgba.b - - rgba.r += (max - rgba.r) * adjust if rgba.r isnt max - rgba.g += (max - rgba.g) * adjust if rgba.g isnt max - rgba.b += (max - rgba.b) * adjust if rgba.b isnt max - rgba - -# ## Vibrance -# Similar to saturation, but adjusts the saturation levels in a slightly smarter, more subtle way. -# Vibrance will attempt to boost colors that are less saturated more and boost already saturated -# colors less, while saturation boosts all colors by the same level. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will desaturate the image while values > 0 will saturate it. -# **If you want to completely desaturate the image**, using the greyscale filter is highly -# recommended because it will yield better results. -Filter.register "vibrance", (adjust) -> - adjust *= -1 - - @process "vibrance", (rgba) -> - max = Math.max rgba.r, rgba.g, rgba.b - avg = (rgba.r + rgba.g + rgba.b) / 3 - amt = ((Math.abs(max - avg) * 2 / 255) * adjust) / 100 - - rgba.r += (max - rgba.r) * amt if rgba.r isnt max - rgba.g += (max - rgba.g) * amt if rgba.g isnt max - rgba.b += (max - rgba.b) * amt if rgba.b isnt max - rgba - -# ## Greyscale -# An improved greyscale function that should make prettier results -# than simply using the saturation filter to remove color. It does so by using factors -# that directly relate to how the human eye perceves color and values. There are -# no arguments, it simply makes the image greyscale with no in-between. -# -# Algorithm adopted from http://www.phpied.com/image-fun/ -Filter.register "greyscale", (adjust) -> - @process "greyscale", (rgba) -> - # Calculate the average value of the 3 color channels - # using the special factors - avg = Calculate.luminance(rgba) - - rgba.r = avg - rgba.g = avg - rgba.b = avg - rgba - -# ## Contrast -# Increases or decreases the color contrast of the image. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will decrease contrast while values > 0 will increase contrast. -# The contrast adjustment values are a bit sensitive. While unrestricted, sane adjustment values -# are usually around 5-10. -Filter.register "contrast", (adjust) -> - adjust = Math.pow((adjust + 100) / 100, 2) - - @process "contrast", (rgba) -> - # Red channel - rgba.r /= 255; - rgba.r -= 0.5; - rgba.r *= adjust; - rgba.r += 0.5; - rgba.r *= 255; - - # Green channel - rgba.g /= 255; - rgba.g -= 0.5; - rgba.g *= adjust; - rgba.g += 0.5; - rgba.g *= 255; - - # Blue channel - rgba.b /= 255; - rgba.b -= 0.5; - rgba.b *= adjust; - rgba.b += 0.5; - rgba.b *= 255; - - rgba - -# ## Hue -# Adjusts the hue of the image. It can be used to shift the colors in an image in a uniform -# fashion. If you are unfamiliar with Hue, I recommend reading this -# [Wikipedia article](http://en.wikipedia.org/wiki/Hue). -# -# ### Arguments -# Range is 0 to 100 -# Sometimes, Hue is expressed in the range of 0 to 360. If that's the terminology you're used to, -# think of 0 to 100 representing the percentage of Hue shift in the 0 to 360 range. -Filter.register "hue", (adjust) -> - @process "hue", (rgba) -> - hsv = Convert.rgbToHSV rgba.r, rgba.g, rgba.b - - h = hsv.h * 100 - h += Math.abs adjust - h = h % 100 - h /= 100 - hsv.h = h - - rgb = Convert.hsvToRGB hsv.h, hsv.s, hsv.v - rgb.a = rgba.a - rgb - -# ## Colorize -# Uniformly shifts the colors in an image towards the given color. The adjustment range is from 0 -# to 100. The higher the value, the closer the colors in the image shift towards the given -# adjustment color. -# -# ### Arguments -# This filter is polymorphic and can take two different sets of arguments. Either a hex color -# string and an adjustment value, or RGB colors and an adjustment value. -Filter.register "colorize", -> - if arguments.length is 2 - rgb = Convert.hexToRGB(arguments[0]) - level = arguments[1] - else if arguments.length is 4 - rgb = - r: arguments[0] - g: arguments[1] - b: arguments[2] - - level = arguments[3] - - @process "colorize", (rgba) -> - rgba.r -= (rgba.r - rgb.r) * (level / 100) - rgba.g -= (rgba.g - rgb.g) * (level / 100) - rgba.b -= (rgba.b - rgb.b) * (level / 100) - rgba - -# ## Invert -# Inverts all colors in the image by subtracting each color channel value from 255. No arguments. -Filter.register "invert", -> - @process "invert", (rgba) -> - rgba.r = 255 - rgba.r - rgba.g = 255 - rgba.g - rgba.b = 255 - rgba.b - rgba - -# ## Sepia -# Applies an adjustable sepia filter to the image. -# -# ### Arguments -# Assumes adjustment is between 0 and 100, which represents how much the sepia filter is applied. -Filter.register "sepia", (adjust = 100) -> - adjust /= 100 - - @process "sepia", (rgba) -> - # All three color channels have special conversion factors that - # define what sepia is. Here we adjust each channel individually, - # with the twist that you can partially apply the sepia filter. - rgba.r = Math.min(255, (rgba.r * (1 - (0.607 * adjust))) + (rgba.g * (0.769 * adjust)) + (rgba.b * (0.189 * adjust))); - rgba.g = Math.min(255, (rgba.r * (0.349 * adjust)) + (rgba.g * (1 - (0.314 * adjust))) + (rgba.b * (0.168 * adjust))); - rgba.b = Math.min(255, (rgba.r * (0.272 * adjust)) + (rgba.g * (0.534 * adjust)) + (rgba.b * (1- (0.869 * adjust)))); - - rgba - -# ## Gamma -# Adjusts the gamma of the image. -# -# ### Arguments -# Range is from 0 to infinity, although sane values are from 0 to 4 or 5. -# Values between 0 and 1 will lessen the contrast while values greater than 1 will increase it. -Filter.register "gamma", (adjust) -> - @process "gamma", (rgba) -> - rgba.r = Math.pow(rgba.r / 255, adjust) * 255 - rgba.g = Math.pow(rgba.g / 255, adjust) * 255 - rgba.b = Math.pow(rgba.b / 255, adjust) * 255 - rgba - -# ## Noise -# Adds noise to the image on a scale from 1 - 100. However, the scale isn't constrained, so you -# can specify a value > 100 if you want a LOT of noise. -Filter.register "noise", (adjust) -> - adjust = Math.abs(adjust) * 2.55 - - @process "noise", (rgba) -> - rand = Calculate.randomRange adjust * -1, adjust - - rgba.r += rand - rgba.g += rand - rgba.b += rand - rgba - -# ## Clip -# Clips a color to max values when it falls outside of the specified range. -# -# ### Arguments -# Supplied value should be between 0 and 100. -Filter.register "clip", (adjust) -> - adjust = Math.abs(adjust) * 2.55 - - @process "clip", (rgba) -> - if rgba.r > 255 - adjust - rgba.r = 255 - else if rgba.r < adjust - rgba.r = 0 - - if rgba.g > 255 - adjust - rgba.g = 255 - else if rgba.g < adjust - rgba.g = 0 - - if rgba.b > 255 - adjust - rgba.b = 255 - else if rgba.b < adjust - rgba.b = 0 - - rgba - -# ## Channels -# Lets you modify the intensity of any combination of red, green, or blue channels individually. -# -# ### Arguments -# Must be given at least one color channel to adjust in order to work. -# Options format (must specify 1 - 3 colors): -#
{
-#   red: 20,
-#   green: -5,
-#   blue: -40
-# }
-Filter.register "channels", (options) -> - return @ if typeof options isnt "object" - - for own chan, value of options - if value is 0 - delete options[chan] - continue - - options[chan] /= 100 - - return @ if options.length is 0 - - @process "channels", (rgba) -> - if options.red? - if options.red > 0 - rgba.r += (255 - rgba.r) * options.red - else - rgba.r -= rgba.r * Math.abs(options.red) - - if options.green? - if options.green > 0 - rgba.g += (255 - rgba.g) * options.green - else - rgba.g -= rgba.g * Math.abs(options.green) - - if options.blue? - if options.blue > 0 - rgba.b += (255 - rgba.b) * options.blue - else - rgba.b -= rgba.b * Math.abs(options.blue) - - rgba - -# ## Curves -# Curves implementation using Bezier curve equation. If you're familiar with the Curves -# functionality in Photoshop, this works in a very similar fashion. -# -# ### Arguments. -#
-#   chan - [r, g, b, rgb]
-#   start - [x, y] (start of curve; 0 - 255)
-#   ctrl1 - [x, y] (control point 1; 0 - 255)
-#   ctrl2 - [x, y] (control point 2; 0 - 255)
-#   end   - [x, y] (end of curve; 0 - 255)
-# 
-# -# The first argument represents the channels you wish to modify with the filter. It can be an -# array of channels or a string (for a single channel). The rest of the arguments are 2-element -# arrays that represent point coordinates. They are specified in the same order as shown in this -# image to the right. The coordinates are in the range of 0 to 255 for both X and Y values. -# -# The x-axis represents the input value for a single channel, while the y-axis represents the -# output value. -Filter.register "curves", (chans, cps...) -> - # If channels are in a string, split to an array - chans = chans.split("") if typeof chans is "string" - chans = ['r', 'g', 'b'] if chans[0] == "v" - - if cps.length < 3 or cps.length > 4 - # might want to give a warning now - throw "Invalid number of arguments to curves filter" - - start = cps[0] - ctrl1 = cps[1] - ctrl2 = if cps.length == 4 then cps[2] else cps[1] - end = cps[cps.length - 1] - - # Generate a bezier curve - bezier = Calculate.bezier start, ctrl1, ctrl2, end, 0, 255 - - # If the curve starts after x = 0, initialize it with a flat line - # until the curve begins. - bezier[i] = start[1] for i in [0...start[0]] if start[0] > 0 - - # ... and the same with the end point - bezier[i] = end[1] for i in [end[0]..255] if end[0] < 255 - - @process "curves", (rgba) -> - # Now that we have the bezier curve, we do a basic hashmap lookup - # to find and replace color values. - rgba[chans[i]] = bezier[rgba[chans[i]]] for i in [0...chans.length] - rgba - -# ## Exposure -# Adjusts the exposure of the image by using the curves function. -# -# ### Arguments -# Range is -100 to 100. Values < 0 will decrease exposure while values > 0 will increase exposure. -Filter.register "exposure", (adjust) -> - p = Math.abs(adjust) / 100 - - ctrl1 = [0, 255 * p] - ctrl2 = [255 - (255 * p), 255] - - if adjust < 0 - ctrl1 = ctrl1.reverse() - ctrl2 = ctrl2.reverse() - - @curves 'rgb', [0, 0], ctrl1, ctrl2, [255, 255] - diff --git a/mig/images/lib/CamanJS-4.1.1/src/lib/size.coffee b/mig/images/lib/CamanJS-4.1.1/src/lib/size.coffee deleted file mode 100644 index 4ff7477ec..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/lib/size.coffee +++ /dev/null @@ -1,63 +0,0 @@ -# Allows us to crop the canvas and produce a new smaller -# canvas. -Caman.Plugin.register "crop", (width, height, x = 0, y = 0) -> - # Create our new canvas element - if exports? - canvas = new Canvas width, height - else - canvas = document.createElement 'canvas' - Util.copyAttributes @canvas, canvas - - canvas.width = width - canvas.height = height - - ctx = canvas.getContext '2d' - - # Perform the cropping by drawing to the new canvas - ctx.drawImage @canvas, x, y, width, height, 0, 0, width, height - - @cropCoordinates = x: x, y: y - - # Update all of the references - @cropped = true - @replaceCanvas canvas - -# Resize the canvas and the image to a new size -Caman.Plugin.register "resize", (newDims = null) -> - # Calculate new size - if newDims is null or (!newDims.width? and !newDims.height?) - Log.error "Invalid or missing dimensions given for resize" - return - - if not newDims.width? - # Calculate width - newDims.width = @canvas.width * newDims.height / @canvas.height - else if not newDims.height? - # Calculate height - newDims.height = @canvas.height * newDims.width / @canvas.width - - if exports? - canvas = new Canvas newDims.width, newDims.height - else - canvas = document.createElement 'canvas' - Util.copyAttributes @canvas, canvas - - canvas.width = newDims.width - canvas.height = newDims.height - - ctx = canvas.getContext '2d' - - ctx.drawImage @canvas, - 0, 0, - @canvas.width, @canvas.height, - 0, 0, - newDims.width, newDims.height - - @resized = true - @replaceCanvas canvas - -Caman.Filter.register "crop", -> - @processPlugin "crop", Array.prototype.slice.call(arguments, 0) - -Caman.Filter.register "resize", -> - @processPlugin "resize", Array.prototype.slice.call(arguments, 0) \ No newline at end of file diff --git a/mig/images/lib/CamanJS-4.1.1/src/plugins/src/idmc.coffee b/mig/images/lib/CamanJS-4.1.1/src/plugins/src/idmc.coffee deleted file mode 100644 index bc69b234b..000000000 --- a/mig/images/lib/CamanJS-4.1.1/src/plugins/src/idmc.coffee +++ /dev/null @@ -1,107 +0,0 @@ -### -IDMC plugins -### - -# resetOriginalPixelData is broken, this is the way it should be - -Caman.Filter.register "idmc_reset_original_pixeldata", () -> - @processPlugin "idmc_reset_original_pixeldata", null - -Caman.Plugin.register "idmc_reset_original_pixeldata", () -> - - Log.debug "idmc_reset_original_pixeldata" - - @originalPixelData = Util.dataArray(@pixelData.length) - @originalPixelData[i] = pixel for pixel, i in @pixelData - @ - -# Adjust minimum and maximim pixel values - -Caman.Filter.register "idmc_set_min_max_pixel_values", (min_pixel_value, max_pixel_value) -> - @processPlugin "idmc_set_min_max_pixel_values", [min_pixel_value, max_pixel_value] - - -Caman.Plugin.register "idmc_set_min_max_pixel_values", (min_pixel_value, max_pixel_value) -> - org_pixels = @originalPixelData - pixels = @pixelData - width = @dimensions.width - height = @dimensions.height - - if not @idmc_set_min_max_pixel_values_r_colormap? - @idmc_set_min_max_pixel_values_r_colormap = (i for i in [0...256]) - - if not @idmc_set_min_max_pixel_values_g_colormap? - @idmc_set_min_max_pixel_values_g_colormap = (i for i in [0...256]) - - if not @idmc_set_min_max_pixel_values_b_colormap? - @idmc_set_min_max_pixel_values_b_colormap = (i for i in [0...256]) - - r_colormap = @idmc_set_min_max_pixel_values_r_colormap - g_colormap = @idmc_set_min_max_pixel_values_g_colormap - b_colormap = @idmc_set_min_max_pixel_values_b_colormap - - - idx = (x,y) => (y*width + x) * 4 - - for i in [0...256] - #Log.debug "i: " +i+ ", " +min_pixel_value+ ", " + "max_pixel_value" - - - index = Math.round((256 * (i - min_pixel_value)) / (max_pixel_value - min_pixel_value)); - #Log.debug "index1: " +index - - index = if index < 0 - 0 - else if i > 255 - 255 - else - index - - #Log.debug "index2: " +index - - r_colormap[i] = if i < min_pixel_value - 0 - else if i > max_pixel_value - 255 - else - index - - g_colormap[i] = if i < min_pixel_value - 0 - else if i > max_pixel_value - 255 - else - index - - b_colormap[i] = if i < min_pixel_value - 0 - else if i > max_pixel_value - 255 - else - index - - - for y in [0...height] - for x in [0...width] - #Log.debug "org_pixels[" +x+ "," +y+ "]: " + org_pixels[idx(x,y)] - - r = org_pixels[idx(x,y)] - g = org_pixels[idx(x,y) + 1] - b = org_pixels[idx(x,y) + 2] - a = org_pixels[idx(x,y) + 3] - - pixels[idx(x,y)] = r_colormap[r] - pixels[idx(x,y) + 1] = g_colormap[g] - pixels[idx(x,y) + 2] = b_colormap[b] - pixels[idx(x,y) + 3] = 255 - - @ - -Caman.Filter.register "idmc_test", () -> - @processPlugin "idmc_test", [] - -Caman.Plugin.register "idmc_test", () -> - @process "idmc_test", (rgba) -> - Log.debug "IDMC test func" - rgba -@ \ No newline at end of file diff --git a/mig/images/lib/ParaView b/mig/images/lib/ParaView deleted file mode 120000 index e5c896f8d..000000000 --- a/mig/images/lib/ParaView +++ /dev/null @@ -1 +0,0 @@ -ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit \ No newline at end of file diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/Visualizer b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/Visualizer deleted file mode 120000 index 15c8f728d..000000000 --- a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/Visualizer +++ /dev/null @@ -1 +0,0 @@ -share/paraview-4.3/www/apps/Visualizer \ No newline at end of file diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/ext b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/ext deleted file mode 120000 index 01b65eae8..000000000 --- a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/ext +++ /dev/null @@ -1 +0,0 @@ -share/paraview-4.3/www/ext \ No newline at end of file diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/lib b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/lib deleted file mode 120000 index b5d20949c..000000000 --- a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/lib +++ /dev/null @@ -1 +0,0 @@ -share/paraview-4.3/www/lib \ No newline at end of file diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/appdata/paraview.appdata.xml b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/appdata/paraview.appdata.xml deleted file mode 100644 index 308a703d9..000000000 --- a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/appdata/paraview.appdata.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - paraview.desktop - CC-BY-4.0 - BSD - -

- ParaView is an open-source, multi-platform data analysis and visualization - application. ParaView users can quickly build visualizations to analyze - their data using qualitative and quantitative techniques. The data - exploration can be done interactively in 3D or programmatically using - ParaView’s batch processing capabilities. -

-

- ParaView was developed to analyze extremely large datasets using distributed - memory computing resources. It can be run on supercomputers to analyze - datasets of exascale size as well as on laptops for smaller data. -

-
- - http://www.paraview.org/wp-content/uploads/2014/04/full_AlegraVV.png - http://www.paraview.org/wp-content/uploads/2014/04/seismic.jpg - http://www.paraview.org/wp-content/uploads/2014/04/full_PolarVortexBreakdown.png - http://www.paraview.org/wp-content/uploads/2014/04/full_hydrodynamic_simulation.png - http://www.paraview.org/wp-content/uploads/2014/04/0_full_Fire.png - - http://paraview.org - paraview-developers@paraview.org -
diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/applications/paraview.desktop b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/applications/paraview.desktop deleted file mode 100644 index cc50e9d37..000000000 --- a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/applications/paraview.desktop +++ /dev/null @@ -1,7 +0,0 @@ -[Desktop Entry] -Version=4.3.1-965-g513d15e -Type=Application -Name=ParaView -Comment=Parallel visualization application -TryExec=paraview -Icon=paraview diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/icons/hicolor/22x22/apps/paraview.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/icons/hicolor/22x22/apps/paraview.png deleted file mode 100644 index 39ef15138..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/icons/hicolor/22x22/apps/paraview.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/icons/hicolor/32x32/apps/paraview.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/icons/hicolor/32x32/apps/paraview.png deleted file mode 100644 index 72f8f183a..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/icons/hicolor/32x32/apps/paraview.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/icons/hicolor/96x96/apps/paraview.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/icons/hicolor/96x96/apps/paraview.png deleted file mode 100644 index 35d7b78b8..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/icons/hicolor/96x96/apps/paraview.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/README.txt b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/README.txt deleted file mode 100644 index f622a833e..000000000 --- a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/README.txt +++ /dev/null @@ -1,21 +0,0 @@ -Icon Sources --------------------- - -data-folder-icon.png http://www.iconarchive.com/show/database-icons-by-fasticon/data-folder-icon.html -Window-Performance-64.png http://www.iconspedia.com/icon/window-performance-icon-37588.html -View-64.png http://www.iconspedia.com/icon/view-icon-20078.html -chart-bar-stacked-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-office-chart-bar-stacked-icon.html -chart-bar-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-office-chart-bar-icon.html -chart-bar-percentage-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-office-chart-bar-percentage-icon.html -chart-line-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-office-chart-line-icon.html -chart-line-stacked-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-office-chart-line-stacked-icon.html -chart-line-percentage-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-office-chart-line-percentage-icon.html -chart-area-stacked-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-office-chart-area-stacked-icon.html -chart-area-percentage-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-office-chart-area-percentage-icon.html -chart-scatter-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-office-chart-scatter-icon.html -go-previous-view-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-go-previous-view-icon.html -go-next-view-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-go-next-view-icon.html -zoom-fit-icon.png http://www.iconarchive.com/show/snowish-icons-by-saki/Actions-zoom-fit-icon.html -system-monitor-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Apps-utilities-system-monitor-icon.html -key-icon.png http://www.iconarchive.com/show/basic-2-icons-by-pixelmixer/key-icon.html -format-stroke-color-icon.png http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/Actions-format-stroke-color-icon.html diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/View-64.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/View-64.png deleted file mode 100644 index 95ae35c0d..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/View-64.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/Window-Performance-64.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/Window-Performance-64.png deleted file mode 100644 index e1b807a47..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/Window-Performance-64.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-area-percentage-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-area-percentage-icon.png deleted file mode 100644 index 72efb796b..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-area-percentage-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-area-stacked-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-area-stacked-icon.png deleted file mode 100644 index 3e7e96ca9..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-area-stacked-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-bar-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-bar-icon.png deleted file mode 100644 index d9de8e93f..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-bar-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-bar-percentage-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-bar-percentage-icon.png deleted file mode 100644 index 74d7da0a0..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-bar-percentage-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-bar-stacked-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-bar-stacked-icon.png deleted file mode 100644 index 4ab7b7c2f..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-bar-stacked-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-line-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-line-icon.png deleted file mode 100644 index 40dcdee6f..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-line-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-line-percentage-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-line-percentage-icon.png deleted file mode 100644 index 0b211ff8b..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-line-percentage-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-line-stacked-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-line-stacked-icon.png deleted file mode 100644 index 414ceedc2..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-line-stacked-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-scatter-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-scatter-icon.png deleted file mode 100644 index 9a0791666..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/chart-scatter-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/data-folder-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/data-folder-icon.png deleted file mode 100644 index a6122f8fc..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/data-folder-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/format-stroke-color-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/format-stroke-color-icon.png deleted file mode 100644 index dcbf60643..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/format-stroke-color-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/go-next-view-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/go-next-view-icon.png deleted file mode 100644 index 7a1247be6..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/go-next-view-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/go-previous-view-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/go-previous-view-icon.png deleted file mode 100644 index b8dbd2926..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/go-previous-view-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/key-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/key-icon.png deleted file mode 100644 index ec7097253..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/key-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/system-monitor-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/system-monitor-icon.png deleted file mode 100644 index f3b50417c..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/system-monitor-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/zoom-fit-icon.png b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/zoom-fit-icon.png deleted file mode 100644 index 8bfadad9b..000000000 Binary files a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/icons/zoom-fit-icon.png and /dev/null differ diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/index.html b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/index.html deleted file mode 100644 index baf8ddce5..000000000 --- a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/index.html +++ /dev/null @@ -1,349 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
-
-
-
-
-
- -
-

- Select dataset to load for probing. Any previously loaded dataset - will be unloaded. -

-

-

-

Connecting ...

-
-
- - - - diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/jclv/LICENSE.txt b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/jclv/LICENSE.txt deleted file mode 100644 index 3b180f2ae..000000000 --- a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/jclv/LICENSE.txt +++ /dev/null @@ -1,25 +0,0 @@ -Copyright 2011 Alexander Khizha. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are -permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of - conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list - of conditions and the following disclaimer in the documentation and/or other materials - provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY ALEXANDER KHIZHA ''AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALEXANDER KHIZHA OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those of the -authors and should not be interpreted as representing official policies, either expressed -or implied, of Alexander Khizha. \ No newline at end of file diff --git a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/jclv/README.txt b/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/jclv/README.txt deleted file mode 100644 index 13388f3fa..000000000 --- a/mig/images/lib/ParaView-4.3.1-965-g513d15e-Qt4-Linux-64bit/share/paraview-4.3/www/apps/DataProber/jclv/README.txt +++ /dev/null @@ -1,99 +0,0 @@ -jColumnListView - -Author: Alexander Khizha -License: BSD - -Description -Simple Finder-like control that can be used instead of element for each checked item, so you can grab an array of elements on the server. Uses a separate CSS with class names prefixed with 'cvl-'. - -Demo site -http://knell.ho.ua/jcvl/ - -Issues and Wishes -Please, feel free to contact me by e-mail (can be found in .js file) or create an issue in case you found some errors or want some features to be implemented. - -Version 0.2 -Splitters added for column. Now it's possible to set min and max width of columns, enable useSplitters flag and change column width with mouse dragging. Also leftMode is available, in this mode only left column will be modified. - -Version 0.2.3 -Added function setValues(). It allows to set up checked items with given values. This function will search for items, makes it checked and sets labels. - -Version 0.2.4 -Implemented single check mode. Set 'singleCheck' parameter to true and only one item can be check at one time. - -Version 0.3 -Implemented auto-scroll. It works in two ways: - -If you click item with children and new column will not fit view area then view will be scrolled to show new column completely. -If you click item without children or empty space of column and current column does not fit view area then view will be scrolled to show current column completely. -Fixed removing of check marks for children items. - -Version 0.3.1 -Implemented support of values for items. Now control can read 'itemValue' attribute for
  • items in list. See updated example below. If attribute 'itemValue' is not present then text will take as value. -Removed dependency on comma (,) item's text or value. Now it's possible to set text for item with commas, and for values too. Also, it will be useful for similar items in different categories. Now you can set different values for them. -Version 0.4 (0.3.2) -Implemented 'leafMode'. If this mode enabled control will store only leaf elements (that have not any children items). Version 0.3.2 promoted to 0.4 (Today is 04.04 :)). - -Version 0.4.1 -From version 0.4.1 it's possible to set up format of item's text. There are three parameters to do it. - -textFormat. It supports two meta tags: %cvl-text% and %cvl-children-counter%. First tag will be replaced with item's text. Second one will be replaced with children counter, obvious, heh? By default this parameter has value %cvl-text% and item will have only text. But you can add any text that you want, for example: 'Item %cvl-text% has %cvl-children-counter% item(s)'. -childrenCounterFormat. This string defines a format for children counter. This parameter supports only one meta tag %cvl-count% which will be replaced with number of children of current item. For example, you can set this format '[%cvl-count%]' and textFormat to '%cvl-children-counter% %cvl-text%' and you will get items like '[3] First Item', '[7] Another Item' or '[5] Third Item'. -emptyChildrenCounter. Flag is used when item has no children. If this parameter is true then %cvl-children-counter% tag will be rendered when children number is 0. Otherwise it will be removed. For example, suppose textFormat is '%cvl-children-counter% %cvl-text%' and childrenCounterFormat is '[ %cvl-count% ]' and our item has no children. So, if emptyChildrenCounter is true then you will get '[ 0 ] Item Text' and 'Item Text' otherwise. -You can change parameters of each column item and of whole column separately. Imagine you have created control and have variable 'cl': - -// Single item -cl.getColumnList().getColumn(0).getItem(2).setChildrenCounterFormat('{%cvl-count%}'); -cl.getColumnList().getColumn(1).getItem(1).setChildrenCounterFormat('=%cvl-count%='); - -// Whole columns -cl.getColumnList().getColumn(0).setChildrenCounterFormat('[%cvl-count%]'); -cl.getColumnList().getColumn(0).setTextFormat('%cvl-children-counter% %cvl-text%'); -cl.getColumnList().getColumn(0).setEmptyChildrenCounter(true); -cl.getColumnList().getColumn(1).setChildrenCounterFormat('{ %cvl-count% }'); -cl.getColumnList().getColumn(1).setTextFormat('%cvl-text% %cvl-children-counter%'); -And, of course, you can change tags! It stored in global object jCVL_ColumnItemTags and by default it looks like: - -var jCVL_ColumnItemTags = { - 'text': '%cvl-text%', - 'childrenCounter': '%cvl-children-counter%', - 'childrenNumber': '%cvl-count%' -}; -So, you can simply do the following: - -jCVL_ColumnItemTags.text = '$my-text-tag$'; -jCVL_ColumnItemTags.childrenCounter = '$my-kids-counter$'; -columnItem.setTextFormat('Item: $my-text-tag$ $my-kids-counter$'); -// Items will be update automatically -Note. Take in mind that global tag's object is used by all jColumnListView controls, so your changes will affect all control instances and probably you will need to update formats everywhere. - -Version 0.4.2 -Implemented visual indicator for items with children. There are two parameters childIndicator and childIndicatorTextFormat. First parameter specifies to show or not children indicator. Second parameter defines a format for text in indicator. If second parameter is null text will not be rendered. This format supports only one tag %cvl-count%. See new screenshots below. -Added two CSS classes: cvl-column-item-indicator and cvl-column-item-indicator-selected. Use these classes to customize your indicator. Structure of text label with indicator element: - - Motherboards -
    -
    -Functions for operate on text formats (0.4.1) and children indicator (0.4.2) implemented for Item, Column and ColumnList. You can easily change look of control: -// List -cl.getColumnList().setChildIndicator(false) -// Column -cl.getColumnList().getColumn(0).setChildIndicator(true) -cl.getColumnList().getColumn(0).setChildIndicatorTextFormat('A') -// Item -cl.getColumnList().getColumn(0).getItem(2).setChildIndicatorTextFormat('(%cvl-count%)') -cl.getColumnList().getColumn(0).getItem(3).setChildIndicatorTextFormat('[%cvl-count%]') -Version 0.5.0 -Basic AJAX support. Added ajaxSource option to configure AJAX request and setFromURL() to load data in list by URL. ajaxSource objects contains of following parameters: -url - URL to get data. By default is null. See notes below. -method - 'GET' or 'POST'. -dataType - Type of data from URL. See notes below. -waiterClass - class name for waiter element (e.g., load spinner). See CSS file for example. -onSuccess - callback to be called when data retrieved successfuly and after this data setted to list. -onFailure - callback to be called when some errors occured during request. -Both of callbacks has the same signature: - function onSuccess(reqObj, respStatus, respData) - function onFailure(reqObj, respStatus, errObj) -where reqObj is an XMLHttpRequest, respStatus is a text status, respData is a data object with required type, errObj is an error object. (See jQuery.ajax() for more details about dataType and callbacks). -New setFromURL() function of jCVL_ColumnListView object. When you create a list view object you can leave ajaxSource.url field empty (null). Control will be constructed without any data, but required parameters for AJAX will be ready for use (method, callbacks, etc). Later you just call to setFromURL(data_url) and your control will be filled with data. -Notes. Now only whole list update is supported. Request must returns simple HTML fragment with