This commit is contained in:
viliusle 2013-08-13 21:56:34 +03:00
parent e4516734c7
commit 70e5ad7862
16 changed files with 2204 additions and 1024 deletions

View File

@ -2,13 +2,17 @@ miniPaint - Online graphics editing tool using HTML5.
Demo: http://viliusle.github.io/miniPaint/
Built using HTML5, JavaScript, Canvas, Drag and Drop, Files API, Offline Support.
Online graphics editing tool use HTML5 technologies like Canvas, Offline support,
Drag and Drop.
Features: open, edit, save images, various drawing tools like Magic Wand tool, Clone tool,
erase, fill, colour picker, colour selector, layers, pencil, brush, shapes, trim, flip,
rotate, resize, Lanczos resample, transparency, zoom, grid, EXIF data, crop,
export/import layers data, paste from clipboard, 25 various filters including blur, Tilt Shift.
erase, fill, color picker, colour selector, layers, pencil, brush, shapes, trim, flip,
rotate, resize, transparency, zoom, grid, EXIF data, crop, export/import layers data,
paste from clipboard, 30 various filters including blur, Tilt Shift, perspective,
denoise, vignette, auto colorize, auto adjust colors, decrease color deapth, histogram,
gradients, fast Hermite resample.
Key features: layers, transparency, offline graphics editing.
@ -16,8 +20,8 @@ It works in all modern browsers that support HTML5.
Used libraries:
JQuery http://jquery.com/
Menu http://blog.geotitles.com/2011/09/creating-the-new-top-black-bar-found-in-google-and-all-its-products/
Google Menu http://blog.geotitles.com/2011/09/creating-the-new-top-black-bar-found-in-google-and-all-its-products/
ImageFilters.js https://github.com/arahaya/ImageFilters.js
glfx.js http://evanw.github.io/glfx.js/
html5slider.js https://github.com/fryn/html5slider
exif.js https://github.com/jseidelin/exif-js
harmony.js http://ricardocabello.com/blog/post/689

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -3,7 +3,7 @@
<head>
<title>miniPaint - online image editor</title>
<meta name="description" content="miniPaint is free online image editor using HTML5. Edit, adjust your images, add effects online in your browser, without installing anything..." />
<meta name="keywords" content="photo, image, picture, free, edit, html5, online, photoshop, gimp, effects, sharpen, blur, magic wand tool, clone tool, rotate, resize, photoshop online, online tools, tilt shift" />
<meta name="keywords" content="photo, image, picture, transparent, layers, free, edit, html5, canvas, javascript, online, photoshop, gimp, effects, sharpen, blur, magic wand tool, clone tool, rotate, resize, photoshop online, online tools, tilt shift, auto colorize" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="styles/styles.css" />
<link rel="stylesheet" type="text/css" media="print" href="styles/print.css" />
@ -18,7 +18,14 @@
</div>
<div id="canvas_container">
<div id="menu_left">
<div id="menu_left_container"></div>
<div id="menu_left_container">
<noscript>
Select object tool, Select area tool, Magic Wand Tool,
Erase, Fill, Pick Color, Pencil, Draw line, Draw letters,
Draw rectangle, Draw circle, Brush, Blur tool, Sharpen tool,
Clone tool, Gradient
</noscript>
</div>
<div style="clear:both;"></div>
<div id="main_colour" onclick="TOOLS.toggle_color_select();"></div>
<div style="margin-top:10px;padding:3px 0px 3px 3px;" class="block" id="all_colors"></div>
@ -27,7 +34,8 @@
<div id="main_colour_rgb">
Red: <input id="rgb_r" onKeyUp="TOOLS.set_color_rgb(this, 'r')" type="text" value="255" /><br />
Green: <input id="rgb_g" onKeyUp="TOOLS.set_color_rgb(this, 'g')" type="text" value="255" /><br />
Blue: <input id="rgb_b" onKeyUp="TOOLS.set_color_rgb(this, 'b')" type="text" value="255" />
Blue: <input id="rgb_b" onKeyUp="TOOLS.set_color_rgb(this, 'b')" type="text" value="255" /><br />
Alpha: <input id="rgb_a" onKeyUp="TOOLS.set_color_rgb(this, 'a')" type="text" value="255" />
</div>
</div>
<div class="block" id="info"></div>
@ -41,7 +49,7 @@
<input onclick="DRAW.zoom(+1);" style="width:30px;" class="layer_add" type="button" value="+" />
<b>Zoom: </b><span id="zoom_nr">100</span>%
<br />
<input id="zoom_range" type="range" value="100" min="50" max="1000" step="50" oninput="DRAW.zoom(this.value);" />
<input style="width:95%;" id="zoom_range" type="range" value="100" min="50" max="1000" step="50" oninput="DRAW.zoom(this.value);" />
</div>
</div>
<div id="layers_base">
@ -78,7 +86,6 @@
<a href="#">Edit</a>
<ul>
<li><a onclick="MENU.do_menu(['edit_undo']);" href="#">Undo</a></li>
<li><a onclick="MENU.do_menu(['edit_redo']);" href="#">Redo</a></li>
<li><div class="mid-line"></div></li>
<li><a onclick="MENU.do_menu(['edit_cut']);" href="#">Cut</a></li>
<li><a onclick="MENU.do_menu(['edit_copy']);" href="#">Copy</a></li>
@ -91,6 +98,7 @@
<li>
<a href="#">Image</a>
<ul>
<li><a onclick="MENU.do_menu(['image_information']);" href="#">Information...</a></li>
<li><a onclick="MENU.do_menu(['image_size']);" href="#">Size...</a></li>
<li><a onclick="MENU.do_menu(['image_trim']);" href="#">Trim</a>
<li><a onclick="MENU.do_menu(['image_crop']);" href="#">Crop Selection</a>
@ -101,10 +109,12 @@
<li><a onclick="MENU.do_menu(['image_rotate']);" href="#">Custom Rotation...</a></li>
<li><a onclick="MENU.do_menu(['image_vflip']);" href="#">Vertical Flip</a></li>
<li><a onclick="MENU.do_menu(['image_hflip']);" href="#">Horizontal Flip</a></li>
<li><a onclick="MENU.do_menu(['image_histogram']);" href="#">Histogram...</a></li>
<li><div class="mid-line"></div></li>
<li><a onclick="MENU.do_menu(['image_colors']);" href="#">Color corrections...</a></li>
<li><a onclick="MENU.do_menu(['image_auto_adjust']);" href="#">Auto adjust colors</a></li>
<li><a onclick="MENU.do_menu(['image_decrease_colors']);" href="#">Decrease color depth...</a></li>
<li><a onclick="MENU.do_menu(['image_negative']);" href="#">Negative</a></li>
<li><a onclick="MENU.do_menu(['image_exif']);" href="#">EXIF info...</a></li>
<li><a onclick="MENU.do_menu(['image_grid']);" href="#">Grid...</a></li>
</ul>
</li>
@ -119,19 +129,13 @@
<li><a onclick="MENU.do_menu(['layer_move_up']);" href="#">Move Up</a></li>
<li><a onclick="MENU.do_menu(['layer_move_down']);" href="#">Move Down</a></li>
<li><a onclick="MENU.do_menu(['layer_opacity']);" href="#">Opacity...</a></li>
<li><a onclick="MENU.do_menu(['layer_colors']);" href="#">Color corrections...</a></li>
<li><div class="mid-line"></div></li>
<li><a onclick="MENU.do_menu(['layer_rotate_left']);" href="#">Rotate Left</a></li>
<li><a onclick="MENU.do_menu(['layer_rotate_right']);" href="#">Rotate Right</a></li>
<li><a onclick="MENU.do_menu(['layer_rotate']);" href="#">Custom Rotation...</a></li>
<li><a onclick="MENU.do_menu(['layer_vflip']);" href="#">Vertical Flip</a></li>
<li><a onclick="MENU.do_menu(['layer_hflip']);" href="#">Horizontal Flip</a></li>
<li><div class="mid-line"></div></li>
<li><a onclick="MENU.do_menu(['layer_trim']);" href="#">Trim</a></li>
<li><a onclick="MENU.do_menu(['layer_resize']);" href="#">Resize...</a></li>
<li><a onclick="MENU.do_menu(['layer_negative']);" href="#">Negative</a></li>
<li><a onclick="MENU.do_menu(['layer_clear']);" href="#">Clear</a></li>
<li><div class="mid-line"></div></li>
<li><a onclick="MENU.do_menu(['layer_differences']);" href="#">Differences Down</a></li>
<li><a onclick="MENU.do_menu(['layer_sprites']);" href="#">Generate sprites</a></li>
<li><a onclick="MENU.do_menu(['layer_merge_down']);" href="#">Merge Down</a></li>
<li><a onclick="MENU.do_menu(['layer_flatten']);" href="#">Flatten Image</a></li>
@ -140,14 +144,19 @@
<li>
<a href="#">Effects</a>
<ul>
<li><a onclick="MENU.do_menu(['effects_bw']);" href="#">Black and White</a>
<li><a onclick="MENU.do_menu(['effects_bw']);" href="#">Black and White...</a>
<li><div class="mid-line"></div></li>
<li><a onclick="MENU.do_menu(['effects_BoxBlur']);" href="#">Blur-Box...</a>
<li><a onclick="MENU.do_menu(['effects_GaussianBlur']);" href="#">Blur-Gaussian...</a>
<li><a onclick="MENU.do_menu(['effects_StackBlur']);" href="#">Blur-Stack...</a>
<li><a onclick="MENU.do_menu(['effects_zoomblur']);" href="#">Blur-Zoom...</a>
<li><div class="mid-line"></div></li>
<li><a onclick="MENU.do_menu(['effects_BrightnessContrast']);" href="#">Brightness Contrast...</a>
<li><a onclick="MENU.do_menu(['effects_bulge_pinch']);" href="#">Bulge/Pinch...</a>
<li><a onclick="MENU.do_menu(['effects_Channels']);" href="#">Channels...</a>
<li><a onclick="MENU.do_menu(['effects_ColorTransformFilter']);" href="#">Color Transform...</a>
<li><a onclick="MENU.do_menu(['effects_colorize']);" href="#">Colorize...</a></li>
<li><a onclick="MENU.do_menu(['effects_denoise']);" href="#">Denoise...</a>
<li><a onclick="MENU.do_menu(['effects_Desaturate']);" href="#">Desaturate</a>
<li><a onclick="MENU.do_menu(['effects_Dither']);" href="#">Dither...</a>
<li><a onclick="MENU.do_menu(['effects_dot_screen']);" href="#">Dot Screen...</a>
@ -160,17 +169,20 @@
<li><a onclick="MENU.do_menu(['effects_Mosaic']);" href="#">Mosaic...</a>
<li><a onclick="MENU.do_menu(['layer_negative']);" href="#">Negative</a></li>
<li><a onclick="MENU.do_menu(['effects_Oil']);" href="#">Oil...</a>
<li><a onclick="MENU.do_menu(['effects_perspective']);" href="#">Perspective...</a>
<li><a onclick="MENU.do_menu(['effects_Posterize']);" href="#">Posterize...</a>
<li><a onclick="MENU.do_menu(['effects_Sepia']);" href="#">Sepia</a>
<li><a onclick="MENU.do_menu(['effects_Sharpen']);" href="#">Sharpen...</a>
<li><a onclick="MENU.do_menu(['effects_Solarize']);" href="#">Solarize</a>
<li><a onclick="MENU.do_menu(['effects_tilt_shift']);" href="#">Tilt Shift...</a>
<li><a onclick="MENU.do_menu(['effects_vignette']);" href="#">Vignette...</a>
</ul>
</li>
<li>
<a href="#">Help</a>
<ul>
<li><a onclick="MENU.do_menu(['help_shortcuts']);" href="#">Keyboard Shortcuts...</a></li>
<li><a onclick="MENU.do_menu(['help_credits']);" href="#">Credits...</a></li>
<li><a onclick="MENU.do_menu(['help_about']);" href="#">About...</a></li>
</ul>
</li>
@ -183,16 +195,16 @@
<script src="libs/menu.js"></script>
<script src="libs/imagefilters.js"></script>
<script src="libs/glfx.js"></script>
<script src="libs/html5slider.js"></script>
<script src="libs/exif.js"></script>
<script src="libs/exif-binaryajax.js"></script>
<script src="libs/harmony.js"></script>
<script src="js/helpers.js"></script>
<script src="js/popup.js"></script>
<script src="js/controlls.js"></script>
<script src="js/tools.js"></script>
<script src="js/draw.js"></script>
<script src="js/layers.js"></script>
<script src="js/helpers.js"></script>
<script src="js/menu_actions.js"></script>
<script src="js/settings.js"></script>
<script src="js/main.js"></script>

View File

@ -22,15 +22,19 @@ function CONTROLLS_CLASS(){
this.ZOOM_X = 0;
this.ZOOM_Y = 0;
this.mini_rect_data = { w: 0, h:0 };
this.isDrag = false;
this.sr_size = 8; //selected area resize rects size
var autosize = true;
var isDrag = false;
var mouse_click_x = false;
var mouse_click_y = false;
var mouse_x_move_last = false;
var mouse_y_move_last = false;
var resize_all = false;
var mouse_click_valid = false;
var last_pop_click = [0, 0];
var popup_pos_top = 0;
var popup_pos_left = 0;
var popup_dragable = false;
//keyboard actions
this.on_keyboard_action = function(event){
@ -75,6 +79,13 @@ function CONTROLLS_CLASS(){
else if(k == 27){
if(POP != undefined && POP.active == true)
POP.hide();
delete TOOLS.last_line_x;
delete TOOLS.last_line_y;
if(TOOLS.select_data != false){
TOOLS.select_data = false;
canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
TOOLS.select_square_action = '';
}
}
//z - undo
else if(k == 90){
@ -105,12 +116,9 @@ function CONTROLLS_CLASS(){
MENU.rotate_resize_doc(270, WIDTH, HEIGHT);
MENU.rotate_layer({angle: 270}, canvas_active(), WIDTH, HEIGHT);
}
//r - rotate right
else if(k == 82){
MAIN.save_state();
MENU.rotate_resize_doc(90, WIDTH, HEIGHT);
MENU.rotate_layer({angle: 90}, canvas_active(), WIDTH, HEIGHT);
}
//r - resize
else if(k == 82)
MENU.resize_box();
//grid
else if(k==71){
if(MAIN.grid == false)
@ -125,6 +133,7 @@ function CONTROLLS_CLASS(){
MAIN.save_state();
canvas_active().clearRect(TOOLS.select_data.x, TOOLS.select_data.y, TOOLS.select_data.w, TOOLS.select_data.h);
TOOLS.select_data = false;
TOOLS.select_square_action = '';
canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
}
}
@ -133,7 +142,8 @@ function CONTROLLS_CLASS(){
CON.shift_pressed = true;
//ctrl
else if(k==17){
CON.ctrl_pressed = true;
if(CON.ctrl_pressed == false)
CON.ctrl_pressed = true;
if (!window.Clipboard)
pasteCatcher.focus();
}
@ -167,6 +177,13 @@ function CONTROLLS_CLASS(){
else if(k==67){
if(CON.ctrl_pressed == true && TOOLS.select_data != false)
MENU.copy_to_clipboard();
else if(CON.ctrl_pressed == false){
MAIN.save_state();
var param1 = parseInt(3);
var param2 = parseInt(30);
DRAW.colorize(canvas_active(), WIDTH, HEIGHT, param1, param2, true);
DRAW.zoom();
}
}
//v
else if(k==86){
@ -174,6 +191,21 @@ function CONTROLLS_CLASS(){
if(CON.ctrl_pressed == true)
MENU.paste();
}
//f - fix images
else if(k==70){
MAIN.save_state();
DRAW.auto_adjust(canvas_active(), WIDTH, HEIGHT);
}
//h - histogram
else if(k==72){
TOOLS.histogram();
}
//-
else if(k==109)
DRAW.zoom(-1);
//+
else if(k==107)
DRAW.zoom(+1);
DRAW.zoom();
return true;
@ -191,40 +223,48 @@ function CONTROLLS_CLASS(){
else if(k==18)
CON.alt_pressed = false;
}
// mouse_x, mouse_y, event.pageX, event.pageY
this.get_mouse_position = function(event){
var valid = true;
if(event.offsetX) {
mouse_x = event.offsetX;
mouse_y = event.offsetY;
mouse_rel_x = event.offsetX;
mouse_rel_y = event.offsetY;
}
else if(event.layerX) {
mouse_x = event.layerX;
mouse_y = event.layerY;
mouse_rel_x = event.layerX;
mouse_rel_y = event.layerY;
}
else
return false;
if(event.target.id != "canvas_preview"){
if((mouse_x < 200 || mouse_y < 200) && event.target.id != "canvas_front"){
mouse_x = mouse_x - 109;
mouse_y = mouse_y - 34;
valid = false;
}
else if((mouse_x > WIDTH+1 || mouse_y > HEIGHT+1) && event.target.id != "canvas_front"){
mouse_x = mouse_x - 109;
mouse_y = mouse_y - 34;
valid = false;
}
mouse_x = event.pageX;
mouse_y = event.pageY;
var abs_x = event.pageX;
var abs_y = event.pageY;
if(event.target.id == "canvas_front"){
//in canvas area - relative pos
mouse_x = mouse_rel_x;
mouse_y = mouse_rel_y;
if(ZOOM != 100 ){
mouse_x = Math.floor(mouse_x / ZOOM * 100);
mouse_y = Math.floor(mouse_y / ZOOM * 100);
mouse_y = Math.floor(mouse_y / ZOOM * 100);
}
}
else
else{
//outside canvas - absolute pos - canvas offset
mouse_x = mouse_x - 109;
mouse_y = mouse_y - 34;
valid = false;
}
if(event.target.id == "canvas_preview"){
//in preview area - relative pos
mouse_x = mouse_rel_x;
mouse_y = mouse_rel_y;
}
//save - other place will use it too
CON.mouse = {
x: mouse_x,
x: mouse_x,
y: mouse_y,
click_x: mouse_click_x,
click_y: mouse_click_y,
@ -232,14 +272,16 @@ function CONTROLLS_CLASS(){
last_y: mouse_y_move_last,
valid: valid,
click_valid: mouse_click_valid,
abs_x: abs_x,
abs_y: abs_y,
};
}
//mouse right click
this.mouse_right_click = function(event){
if(POP != undefined && POP.active==true) return true;
mouse_click_x = mouse_x;
mouse_click_y = mouse_y;
CON.get_mouse_position(event);
mouse_click_x = CON.mouse.x;
mouse_click_y = CON.mouse.y;
for (i in TOOLS){
if(i == ACTION){
@ -250,16 +292,29 @@ function CONTROLLS_CLASS(){
}
//mouse click
this.mouse_click = function(event){
if(POP != undefined && POP.active==true) return true;
CON.isDrag = true;
if(POP != undefined && POP.active==true){
CON.get_mouse_position(event);
last_pop_click[0] = CON.mouse.abs_x;
last_pop_click[1] = CON.mouse.abs_y;
popup = document.getElementById('popup');
popup_pos_top = parseInt(popup.style.top);
popup_pos_left = parseInt(popup.style.left);
if(event.target.id == "popup_drag")
popup_dragable = true;
else
popup_dragable = false;
return true;
}
if(event.which == 3) return true;
mouse_click_x = mouse_x;
mouse_click_y = mouse_y;
CON.get_mouse_position(event);
mouse_click_x = CON.mouse.x;
mouse_click_y = CON.mouse.y;
if(CON.mouse.valid == false)
mouse_click_valid = false;
else
mouse_click_valid = true;
isDrag = true;
//check tools functions
for (i in TOOLS){
@ -282,9 +337,18 @@ function CONTROLLS_CLASS(){
}
//mouse move
this.mouse_move = function(event){
if(POP != undefined && POP.active==true) return true;
if(POP != undefined && POP.active==true){
//drag popup
if(CON.isDrag==true && popup_dragable == true){
CON.get_mouse_position(event);
popup = document.getElementById('popup');
popup.style.top = (popup_pos_top + CON.mouse.abs_y - last_pop_click[1])+'px';
popup.style.left = (popup_pos_left + CON.mouse.abs_x - last_pop_click[0])+'px';
}
return true;
}
CON.get_mouse_position(event);
if(event.target.id == "canvas_preview" && isDrag==true)
if(event.target.id == "canvas_preview" && CON.isDrag==true)
CON.calc_preview_by_mouse(CON.mouse.x, CON.mouse.y);
LAYER.update_info_block();
@ -294,21 +358,23 @@ function CONTROLLS_CLASS(){
else if(event.target.id == "resize-h") document.body.style.cursor = "n-resize";
else if(event.target.id == "resize-wh") document.body.style.cursor = "nw-resize";
else document.body.style.cursor = "auto";
if(resize_all != false && isDrag==true){
if(resize_all != false && CON.isDrag==true){
document.body.style.cursor = "auto";
if(resize_all == "w"){
new_w = mouse_x;
new_w = CON.mouse.x;
new_h = HEIGHT;
}
else if(resize_all == "h"){
new_w = WIDTH;
new_h = mouse_y;
new_h = CON.mouse.y;
}
else if(resize_all == "wh"){
new_w = mouse_x;
new_h = mouse_y;
new_w = CON.mouse.x;
new_h = CON.mouse.y;
}
canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
canvas_front.lineWidth = 1;
canvas_front.fillStyle = "#ff0000";
HELPER.dashedRect(canvas_front, 0, 0, new_w-1, new_h-1);
event.preventDefault();
HELPER.remove_selection();
@ -316,16 +382,15 @@ function CONTROLLS_CLASS(){
}
}
//check tools functions
if(isDrag === false){
for (i in TOOLS){
if(i == ACTION){
TOOLS[i]('move', CON.mouse, event);
break;
}
for (i in TOOLS){
if(i == ACTION){
TOOLS[i]('move', CON.mouse, event);
break;
}
}
if(isDrag === false) return false; //only drag now
if(CON.isDrag === false) return false; //only drag now
//check tools functions
for (i in TOOLS){
@ -337,15 +402,17 @@ function CONTROLLS_CLASS(){
if(ACTION != 'select_square')
TOOLS.select_square_action = '';
mouse_x_move_last = CON.mouse.x;
mouse_y_move_last = CON.mouse.y;
}
//release mouse click
this.mouse_release = function(event){
CON.isDrag = false;
if(POP != undefined && POP.active==true) return true;
var mouse = CON.get_mouse_position(event);
isDrag = false;
mouse_x_move_last = false
mouse_y_move_last = false;
if(TOOLS.select_square_action == '' && CON.mouse.valid == true)
@ -362,16 +429,16 @@ function CONTROLLS_CLASS(){
}
//main window resize
if(resize_all != false && ZOOM == 100){
if(resize_all != false && ZOOM == 100 && CON.mouse.x > 0 && CON.mouse.y > 0){
CON.autosize = false;
document.body.style.cursor = "auto";
if(resize_all == "w")
WIDTH = parseInt(mouse_x);
WIDTH = CON.mouse.x;
else if(resize_all == "h")
HEIGHT = parseInt(mouse_y);
HEIGHT = CON.mouse.y;
else if(resize_all == "wh"){
WIDTH = parseInt(mouse_x);
HEIGHT = parseInt(mouse_y);
WIDTH = mouse_x;
HEIGHT = CON.mouse.y;
}
RATIO = WIDTH/HEIGHT;
LAYER.set_canvas_size();
@ -387,8 +454,10 @@ function CONTROLLS_CLASS(){
progress.style.display='block';
progress.value = progress.innerHTML = 0;
MAIN.save_state();
var n_valid = 0;
for (var i = 0, f; f = e.dataTransfer.files[i]; i++){
if(!f.type.match('image.*') && f.type != 'text/xml') continue;
n_valid++;
var FR = new FileReader();
FR.file = e.dataTransfer.files[i];
@ -425,6 +494,8 @@ function CONTROLLS_CLASS(){
else
FR.readAsDataURL(f);
}
if(n_valid == 0)
progress.style.display='none';
document.getElementById("drop_zone").style.display='none';
}
this.mouse_wheel_handler = function(e){ //return true;

View File

@ -6,7 +6,7 @@ function DRAW_CLASS(){
this.draw_grid = function(canvas, gap_x, gap_y){
if(MAIN.grid == false){
canvas.clearRect(0, 0, WIDTH, HEIGHT);
DRAW.draw_background(canvas);
DRAW.draw_background(canvas, WIDTH, HEIGHT);
return false;
}
gap_x = parseInt(gap_x);
@ -36,10 +36,10 @@ function DRAW_CLASS(){
canvas.stroke();
}
}
this.draw_background = function(canvas, gap, force){
this.draw_background = function(canvas, W, H, gap, force){
if(MAIN.TRANSPARENCY == false && force == undefined){
canvas.beginPath();
canvas.rect(0, 0, WIDTH, HEIGHT);
canvas.rect(0, 0, W, H);
canvas.fillStyle = "#ffffff";
canvas.fill();
return false;
@ -47,12 +47,12 @@ function DRAW_CLASS(){
if(gap == undefined)
gap = 10;
var fill = true;
for(var i=0; i<WIDTH; i=i+gap){
for(var i=0; i<W; i=i+gap){
if(i%(gap*2) == 0)
fill=true;
else
fill=false;
for(var j=0; j<HEIGHT; j=j+gap){
for(var j=0; j<H; j=j+gap){
if(fill==true){
canvas.fillStyle = '#eeeeee';
canvas.fillRect(i, j, gap, gap);
@ -103,7 +103,6 @@ function DRAW_CLASS(){
imgData[k+1] = color_to.g; //g
imgData[k+2] = color_to.b; //b
imgData[k+3] = color_to.a; //a
stack.push(nextPointX);
stack.push(nextPointY);
}
@ -134,6 +133,7 @@ function DRAW_CLASS(){
color_from.b == color_to.b &&
color_from.a == color_to.a)
return false;
if(ALPHA < 255 && color_from.a == ALPHA) return false;
var stack = [];
stack.push(x);
stack.push(y);
@ -152,10 +152,14 @@ function DRAW_CLASS(){
Math.abs(imgData[k+2] - color_from.b) <= sensitivity &&
Math.abs(imgData[k+3] - color_from.a) <= sensitivity){
//fill pixel
imgData[k+0] = color_to.r; //r
imgData[k+1] = color_to.g; //g
imgData[k+2] = color_to.b; //b
imgData[k+3] = color_to.a; //a
if(ALPHA == 255){
imgData[k+0] = color_to.r; //r
imgData[k+1] = color_to.g; //g
imgData[k+2] = color_to.b; //b
imgData[k+3] = color_to.a; //a
}
else
imgData[k+3] = ALPHA; //a
stack.push(nextPointX);
stack.push(nextPointY);
@ -164,7 +168,65 @@ function DRAW_CLASS(){
}
context.putImageData(img, 0, 0);
}
this.trim = function(layer, no_resize){
this.trim_info = function(canvas, trim_white, include_white){
var top = 0;
var left = 0;
var bottom = 0;
var right = 0;
var img = canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height);
var imgData = img.data;
//check top
main1:
for(var y = 0; y < img.height; y++){
for(var x = 0; x < img.width; x++){
var k = ((y * (img.width * 4)) + (x * 4));
if(imgData[k+3] == 0) continue; //transparent
if(include_white !== true && imgData[k] == 255 && imgData[k+1] == 255 && imgData[k+2] == 255) continue; //white
break main1;
}
top++;
}
//check left
main2:
for(var x = 0; x < img.width; x++){
for(var y = 0; y < img.height; y++){
var k = ((y * (img.width * 4)) + (x * 4));
if(imgData[k+3] == 0) continue; //transparent
if(include_white !== true && imgData[k] == 255 && imgData[k+1] == 255 && imgData[k+2] == 255) continue; //white
break main2;
}
left++;
}
//check bottom
main3:
for(var y = img.height-1; y >= 0; y--){
for(var x = img.width-1; x >= 0; x--){
var k = ((y * (img.width * 4)) + (x * 4));
if(imgData[k+3] == 0) continue; //transparent
if(include_white !== true && imgData[k] == 255 && imgData[k+1] == 255 && imgData[k+2] == 255) continue; //white
break main3;
}
bottom++;
}
//check right
main4:
for(var x = img.width-1; x >= 0; x--){
for(var y = img.height-1; y >= 0; y--){
var k = ((y * (img.width * 4)) + (x * 4));
if(imgData[k+3] == 0) continue; //transparent
if(include_white !== true && imgData[k] == 255 && imgData[k+1] == 255 && imgData[k+2] == 255) continue; //white
break main4;
}
right++;
}
return {
top: top,
left: left,
bottom: bottom,
right: right,
};
};
this.trim = function(layer, no_resize, include_white){
var all_top = HEIGHT;
var all_left = WIDTH;
var all_bottom = HEIGHT;
@ -183,18 +245,20 @@ function DRAW_CLASS(){
for(var y = 0; y < img.height; y++){
for(var x = 0; x < img.width; x++){
var k = ((y * (img.width * 4)) + (x * 4));
if(imgData[k+3]>0 && (imgData[k]<255 || imgData[k+1]<255 || imgData[k+2]<255) )
break main1;
if(imgData[k+3] == 0) continue; //transparent
if(include_white !== true && imgData[k] == 255 && imgData[k+1] == 255 && imgData[k+2] == 255) continue; //white
break main1;
}
top++;
}
//check left
main2:
for(var x = 0; x < img.width; x++){
for(var x = 0; x < img.width; x++){
for(var y = 0; y < img.height; y++){
var k = ((y * (img.width * 4)) + (x * 4));
if(imgData[k+3]>0 && (imgData[k]<255 || imgData[k+1]<255 || imgData[k+2]<255) )
break main2;
if(imgData[k+3] == 0) continue; //transparent
if(include_white !== true && imgData[k] == 255 && imgData[k+1] == 255 && imgData[k+2] == 255) continue; //white
break main2;
}
left++;
}
@ -203,8 +267,9 @@ function DRAW_CLASS(){
for(var y = img.height-1; y >= 0; y--){
for(var x = img.width-1; x >= 0; x--){
var k = ((y * (img.width * 4)) + (x * 4));
if(imgData[k+3]>0 && (imgData[k]<255 || imgData[k+1]<255 || imgData[k+2]<255) )
break main3;
if(imgData[k+3] == 0) continue; //transparent
if(include_white !== true && imgData[k] == 255 && imgData[k+1] == 255 && imgData[k+2] == 255) continue; //white
break main3;
}
bottom++;
}
@ -213,8 +278,9 @@ function DRAW_CLASS(){
for(var x = img.width-1; x >= 0; x--){
for(var y = img.height-1; y >= 0; y--){
var k = ((y * (img.width * 4)) + (x * 4));
if(imgData[k+3]>0 && (imgData[k]<255 || imgData[k+1]<255 || imgData[k+2]<255) )
break main4;
if(imgData[k+3] == 0) continue; //transparent
if(include_white !== true && imgData[k] == 255 && imgData[k+1] == 255 && imgData[k+2] == 255) continue; //white
break main4;
}
right++;
}
@ -261,18 +327,358 @@ function DRAW_CLASS(){
}
LAYER.update_info_block();
}
this.effect_bw = function(context, W, H){
var threshold = 200;
this.effect_bw = function(context, W, H, level){
var black = level + 25; //default 150;
var white = level - 25; //defaul 100;
if(black < 0 || level == 0) black = 0;
if(white > 255 || level == 255) white = 255;
var img = context.getImageData(0, 0, W, H);
var imgData = img.data;
for(var i = 0; i < imgData.length; i += 4) {
var c = imgData[i] > threshold ? 255 : 0;
imgData[i] = c;
imgData[i+1] = c;
imgData[i+2] = c;
var imgData = img.data;
for(var j = 0; j < H; j++){
for(var i = 0; i < W; i++){
var x = (i + j*W) * 4;
if(imgData[x+3] == 0) continue; //transparent
var c = 0;
var mid = round(imgData[x] + imgData[x+1] + imgData[x+2])/3;
if(mid >= black)
c = 255;
else if(mid <= white)
c = 0;
else{
//we not sure here ... randomize to get better overall quality
c = HELPER.getRandomInt(white, black);
if(mid < c)
c = 0;
else
c = 255;
}
imgData[x] = c;
imgData[x+1] = c;
imgData[x+2] = c;
}
}
context.putImageData(img, 0, 0);
}
this.decrease_colors = function(context, W, H, colors, dithering, greyscale){
var img = context.getImageData(0, 0, W, H);
var imgData = img.data;
//collect top colors
var colors_top = [];
for(var i = 0; i < imgData.length; i += 40){ //check pixel and skip 10.
if(imgData[i+3] == 0) continue; //transparent
var key = imgData[i]+"."+imgData[i+1]+"."+imgData[i+2];
if(colors_top[key] == undefined)
colors_top[key] = [1, imgData[i], imgData[i+1], imgData[i+2]];
else
colors_top[key][0]++;
}
//sort
colors_top.sort(function(a,b) { return parseFloat(b[0]) - parseFloat(a[0]); } );
var colors_top_sort = [];
for (var i in colors_top)
colors_top_sort.push(colors_top[i]);
colors_top_sort.sort(function(a, b) {return b[0] - a[0]});
colors_top = colors_top_sort; //alert(colors_top.length);
if(colors_top.length > 256){
var last = colors_top[0];
for(var i=1; i<colors_top.length; i++){
var diffR = colors_top[i][1] - last[1];
var diffG = colors_top[i][2] - last[2];
var diffB = colors_top[i][3] - last[3];
diff = Math.sqrt(diffR*diffR + diffG*diffG + diffB*diffB);
if(diff > 100)
last = colors_top[i]; //save last good
else{
//to close, remove it
colors_top.splice(i, 1); i--;
}
}
if(colors_top.length < 100){
//oops, we deleted too much ...
colors_top = colors_top_sort;
colors_top_sort.splice(256);
}
colors_top_sort.splice(512);
}
colors_top_sort = [];
var palette = [];
var min = 0;
var index;
var top_color_n;
for(var i in colors_top){
if(colors_top[i][0] > min){
min = colors_top[0];
index = i;
}
}
//add main color
palette.push([colors_top[index][1], colors_top[index][2], colors_top[index][3]]);
top_color_n = colors_top[index][0];
//increase pallete - use only different colors
for(var c=1; c<colors; c++){
var diff_all=0;
var max_all = 0;
var index_all;
//reset
for(var i in colors_top)
colors_top[i][4] = [];
for(var p in palette){
var diff;
var max = 0;
var index;
var diff_tmp = [];
for(var i in colors_top){
var diffR = colors_top[i][1] - palette[p][0];
var diffG = colors_top[i][2] - palette[p][1];
var diffB = colors_top[i][3] - palette[p][2];
diff = Math.sqrt(diffR*diffR + diffG*diffG + diffB*diffB); //max 441
//density fix
//diff *= colors_top[i][0];// * 441 / top_color_n;
colors_top[i][4].push(diff);
}
}
//find biggest minimum
var index=0;
var max = 0;
for(var i in colors_top){
var min = 999999;
for(var k in colors_top[i][4]){
if(colors_top[i][4][k] < min)
min = colors_top[i][4][k];
}
if(min > max){
index = i;
max = min;
}
}
palette.push([colors_top[index][1], colors_top[index][2], colors_top[index][3]]);
}
//change
for(var i = 0; i < imgData.length; i += 4){
if(imgData[i+3] == 0) continue; //transparent
var mid = round(imgData[i] + imgData[i+1] + imgData[i+2])/3;
if(dithering == true){
//find first close color
var index1 = 0;
var min1 = 256*3;
var diff1;
for(var j=0; j<palette.length; j++){
var diff = 0;
diff += Math.abs(palette[j][0] - imgData[i]);
diff += Math.abs(palette[j][1] - imgData[i+1]);
diff += Math.abs(palette[j][2] - imgData[i+2]);
if(diff < min1){
min1 = diff;
index1 = j;
diff1 = diff;
}
}
//find second close color
var index2 = 0;
var min2 = 256*3;
var diff2;
for(var j=0; j<palette.length; j++){
if(j == index1) continue; //we already have this
var diff = 0;
diff += Math.abs(palette[j][0] - imgData[i]);
diff += Math.abs(palette[j][1] - imgData[i+1]);
diff += Math.abs(palette[j][2] - imgData[i+2]);
if(diff < min2){
min2 = diff;
index2 = j;
diff2 = diff;
}
}
var c;
if(diff1 == 0 || diff1/diff2 < 0.3)
c = palette[index1]; //exact color match
else{
//we not sure here ... randomize to get better overall quality
var rand = HELPER.getRandomInt(-diff1, diff2);
if(rand < 0)
c = palette[index2];
else
c = palette[index1];
}
imgData[i] = c[0];
imgData[i+1] = c[1];
imgData[i+2] = c[2];
}
else{
var index = 0;
var min = 256*3;
for(var j=0; j<palette.length; j++){
var diff = 0;
diff += Math.abs(palette[j][0] - imgData[i]);
diff += Math.abs(palette[j][1] - imgData[i+1]);
diff += Math.abs(palette[j][2] - imgData[i+2]);
if(diff < min){
min = diff;
index = j;
}
}
imgData[i] = palette[index][0];
imgData[i+1] = palette[index][1];
imgData[i+2] = palette[index][2];
}
if(greyscale == true){
var mid = round(0.2126 * imgData[i] + 0.7152 * imgData[i+1] + 0.0722 * imgData[i+2]);
imgData[i] = mid;
imgData[i+1] = mid;
imgData[i+2] = mid;
}
}
context.putImageData(img, 0, 0);
}
//converts greyscale images to coloured
this.colorize = function(context, W, H, rand_power, max_gap, dither, manual_colors){
var img = context.getImageData(0, 0, W, H);
if(manual_colors == undefined || manual_colors === true){
var colors = [];
for(var x=0; x < 3; x++){
colors[x] = [];
var pre = HELPER.getRandomInt(-1 * rand_power, rand_power);
for(var i = 0; i <= 255; i++){
colors[x][i] = HELPER.getRandomInt(pre - rand_power, pre + rand_power);
if(colors[x][i] < -1*max_gap) colors[x][i] += 10;
else if(colors[x][i] > max_gap) colors[x][i] -= 10;
pre = colors[x][i];
}
}
if(manual_colors === true)
return colors;
}
else
var colors = manual_colors;
//colorize
var imgData = img.data;
for(var i = 0; i < imgData.length; i += 4){
if(imgData[i+3] == 0) continue; //transparent
if(dither == true){
var diff = Math.abs(colors[0][imgData[x]]) + Math.abs(colors[0][imgData[x]]) + Math.abs(colors[0][imgData[x]]);
diff = diff / 3;
}
for(var c = 0; c < 3; c++){
var x = i + c;
if(dither == false)
imgData[x] += colors[c][imgData[x]];
else{
if(diff < rand_power*6)
imgData[x] += colors[c][imgData[x]];
else{
//big difference here - randomize
var rand = HELPER.getRandomInt(Math.min(0, colors[c][imgData[x]]), Math.max(0, colors[c][imgData[x]]));
imgData[x] += rand;
}
}
if(imgData[x] > 255) imgData[x] = 255;
if(imgData[x] < 0) imgData[x] = 0;
}
}
context.putImageData(img, 0, 0);
return false;
}
//fixing white and black color balance
this.auto_adjust = function(context, W, H){
//settings
var white = 240; //white color min
var black = 30; //black color max
var target_white = 1; //how much % white colors should take
var target_black = 0.5; //how much % black colors should take
var modify = 1.1; //color modify strength
document.body.style.cursor = "wait";
var img = context.getImageData(0, 0, W, H);
var imgData = img.data;
var n = 0; //pixels count without transparent
//make sure we have white
var n_valid = 0;
for(var i = 0; i < imgData.length; i += 4){
if(imgData[i+3] == 0) continue; //transparent
if((imgData[i] + imgData[i+1] + imgData[i+2]) / 3 > white) n_valid++;
n++;
}
target = target_white;
var n_fix_white = 0;
var done = false;
for(var j=0; j < 30; j++){
if(n_valid * 100 / n >= target) done = true;
if(done == true) break;
n_fix_white++;
//adjust
for(var i = 0; i < imgData.length; i += 4){
if(imgData[i+3] == 0) continue; //transparent
for(var c = 0; c < 3; c++){
var x = i + c;
if(imgData[x] < 10) continue;
//increase white
imgData[x] *= modify;
imgData[x] = round(imgData[x]);
if(imgData[x] > 255) imgData[x] = 255;
}
}
//recheck
n_valid = 0;
for(var i = 0; i < imgData.length; i += 4){
if(imgData[i+3] == 0) continue; //transparent
if((imgData[i] + imgData[i+1] + imgData[i+2]) / 3 > white) n_valid++;
}
}
//make sure we have black
n_valid = 0;
for(var i = 0; i < imgData.length; i += 4){
if(imgData[i+3] == 0) continue; //transparent
if((imgData[i] + imgData[i+1] + imgData[i+2]) / 3 < black) n_valid++;
}
target = target_black;
var n_fix_black = 0;
var done = false;
for(var j=0; j < 30; j++){
if(n_valid * 100 / n >= target) done = true;
if(done == true) break;
n_fix_black++;
//adjust
for(var i = 0; i < imgData.length; i += 4){
if(imgData[i+3] == 0) continue; //transparent
for(var c = 0; c < 3; c++){
var x = i + c;
if(imgData[x] > 240) continue;
//increase black
imgData[x] -= (255-imgData[x]) * modify - (255-imgData[x]);
imgData[x] = round(imgData[x]);
}
}
//recheck
n_valid = 0;
for(var i = 0; i < imgData.length; i += 4){
if(imgData[i+3] == 0) continue; //transparent
if((imgData[i] + imgData[i+1] + imgData[i+2]) / 3 < black) n_valid++;
}
}
//save
context.putImageData(img, 0, 0);
document.body.style.cursor = "auto";
log('Iterations: brighten='+n_fix_white+", darken="+n_fix_black);
}
this.zoom = function(recalc, scroll){
if(recalc != undefined){
//zoom-in or zoom-out
@ -327,7 +733,7 @@ function DRAW_CLASS(){
canvas_preview.rect(0, 0, DRAW.PREVIEW_SIZE.w, DRAW.PREVIEW_SIZE.h);
canvas_preview.fillStyle = "#ffffff";
canvas_preview.fill();
DRAW.draw_background(canvas_preview, 5);
DRAW.draw_background(canvas_preview, DRAW.PREVIEW_SIZE.w, DRAW.PREVIEW_SIZE.h, 5);
//redraw preview area
canvas_preview.save();
@ -369,111 +775,98 @@ function DRAW_CLASS(){
context.lineTo(tox-headlen*Math.cos(angle+Math.PI/6),toy-headlen*Math.sin(angle+Math.PI/6));
context.stroke();
}
//http://stackoverflow.com/questions/2303690/resizing-an-image-in-an-html5-canvas, credits to "syockit"
var object_l = {};
this.thumbnailer = function(elem, sx, lobes){
var img = elem.getContext("2d").getImageData(0, 0, elem.width, elem.height);
object_l.canvas = elem;
object_l.ctx = elem.getContext("2d");
object_l.ctx.putImageData(img, 0, 0);
object_l.img = img;
object_l.src = object_l.ctx.getImageData(0, 0, img.width, img.height);
object_l.dest = {
width: sx,
height: Math.round(img.height * sx / img.width),
};
object_l.dest.data = new Array(object_l.dest.width * object_l.dest.height * 3);
object_l.lanczos = DRAW.lanczosCreate(lobes);
object_l.ratio = img.width / sx;
object_l.rcp_ratio = 2 / object_l.ratio;
object_l.range2 = Math.ceil(object_l.ratio * lobes / 2);
object_l.cacheLanc = {};
object_l.center = {};
object_l.icenter = {};
object_l.date = Date.now();
//setTimeout(this.process1, 0, this, 0); //setTimeout is slow, has big pauses between
DRAW.process1(object_l, 0);
}
//calculates lanczos weight
this.lanczosCreate = function(lobes){
return function(x){
if (x > lobes)
return 0;
x *= Math.PI;
if (Math.abs(x) < 1e-16)
return 1;
var xx = x / lobes;
return Math.sin(x) * Math.sin(xx) / x / xx;
}
}
this.process1 = function(self, u){
//continue
self.center.x = (u + 0.5) * self.ratio;
self.icenter.x = Math.floor(self.center.x);
for (var v = 0; v < self.dest.height; v++) {
self.center.y = (v + 0.5) * self.ratio;
self.icenter.y = Math.floor(self.center.y);
var a, r, g, b, x;
a = r = g = b = x = 0;
for (var i = self.icenter.x - self.range2; i <= self.icenter.x + self.range2; i++) {
if (i < 0 || i >= self.src.width)
continue;
var f_x = Math.floor(1000 * Math.abs(i - self.center.x));
if (!self.cacheLanc[f_x])
self.cacheLanc[f_x] = {};
for (var j = self.icenter.y - self.range2; j <= self.icenter.y + self.range2; j++) {
if (j < 0 || j >= self.src.height)
continue;
var f_y = Math.floor(1000 * Math.abs(j - self.center.y));
if (self.cacheLanc[f_x][f_y] == undefined)
self.cacheLanc[f_x][f_y] = self.lanczos(Math.sqrt(Math.pow(f_x * self.rcp_ratio, 2) + Math.pow(f_y * self.rcp_ratio, 2)) / 1000);
weight = self.cacheLanc[f_x][f_y];
if (weight > 0) {
var idx = (j * self.src.width + i) * 4;
a += weight;
r += weight * self.src.data[idx];
g += weight * self.src.data[idx + 1];
b += weight * self.src.data[idx + 2];
x += weight * self.src.data[idx + 3]; //transparency
}
}
}
var idx = (v * self.dest.width + u) * 4;
self.dest.data[idx] = r / a;
self.dest.data[idx + 1] = g / a;
self.dest.data[idx + 2] = b / a;
self.dest.data[idx + 3] = x / a ; //transparency
}
if (++u < self.dest.width)
DRAW.process1(self, u);
else
DRAW.process2(self, u);
};
this.process2 = function(self){
self.ctx.putImageData(self.img, 0, 0);
self.src = self.ctx.getImageData(0, 0, self.dest.width, self.dest.height);
var idx, idx2;
for (var i = 0; i < self.dest.width; i++) {
for (var j = 0; j < self.dest.height; j++) {
idx = (j * self.dest.width + i) * 4;
idx2 = (j * self.dest.width + i) * 4;
self.src.data[idx2] = self.dest.data[idx];
self.src.data[idx2 + 1] = self.dest.data[idx + 1];
self.src.data[idx2 + 2] = self.dest.data[idx + 2];
self.src.data[idx2 + 3] = self.dest.data[idx + 3]; //transparency
}
}
//var time = Date.now() - self.date;alert(time/1000+"s");
self.ctx.clearRect(0, 0, WIDTH, HEIGHT);
self.ctx.putImageData(self.src, 0, 0);
self = {}; //release memory
//hermite resample - classic "rings.gif" 1000x1000 resize to 200x200 record - 0.040
this.resample_hermite = function(canvas, W, H, W2, H2){
var time1 = Date.now();
var img = canvas.getContext("2d").getImageData(0, 0, W, H);
var img2 = canvas.getContext("2d").getImageData(0, 0, W2, H2);
var data = img.data;
var data2 = img2.data;
var ratio_w = W / W2;
var ratio_h = H / H2;
var ratio_w_half = Math.ceil(ratio_w/2);
var ratio_h_half = Math.ceil(ratio_h/2);
//do some extra things
LAYER.resize_canvas(LAYERS[LAYER.layer_active].name, true);
if(MENU.last_menu == 'image_resize')
DRAW.trim();
DRAW.zoom();
if(POP.active == true)
POP.hide();
}
for(var j = 0; j < H2; j++){
for(var i = 0; i < W2; i++){
var x2 = (i + j*W2) * 4;
var weight = 0;
var weights = 0;
var gx_r = gx_g = gx_b = gx_a = 0;
var center_y = (j + 0.5) * ratio_h;
for(var yy = Math.floor(j * ratio_h); yy < (j + 1) * ratio_h; yy++){
var dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half;
var center_x = (i + 0.5) * ratio_w;
var w0 = dy*dy //pre-calc part of w
for(var xx = Math.floor(i * ratio_w); xx < (i + 1) * ratio_w; xx++){
var dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half;
var w = Math.sqrt(w0 + dx*dx);
if(w >= -1 && w <= 1){
//hermite filter
weight = 2 * w*w*w - 3*w*w + 1;
if(weight > 0){
dx = 4*(xx + yy*W);
gx_r += weight * data[dx];
gx_g += weight * data[dx + 1];
gx_b += weight * data[dx + 2];
gx_a += weight * data[dx + 3];
weights += weight;
}
}
}
}
data2[x2] = gx_r / weights;
data2[x2 + 1] = gx_g / weights;
data2[x2 + 2] = gx_b / weights;
data2[x2 + 3] = gx_a / weights;
}
}
console.log("hermite = "+(Math.round(Date.now() - time1)/1000)+" s");
canvas.getContext("2d").clearRect(0, 0, Math.max(W, W2), Math.max(H, H2));
canvas.getContext("2d").putImageData(img2, 0, 0);
};
this.resample_hermite_threads = function(canvas, W, H, W2, H2){
var time1 = Date.now();
var img = canvas.getContext("2d").getImageData(0, 0, W, H);
var img2 = canvas.getContext("2d").getImageData(0, 0, W2, H2);
var data2 = img2.data;
var cores = 8;
var cpu_in_use = 0;
var progress = document.getElementById('uploadprogress');
progress.style.display='block';
progress.value = progress.innerHTML = 0;
canvas.getContext("2d").clearRect(0, 0, W, H);
for(var c = 0; c < cores; c++){
cpu_in_use++;
var my_worker = new Worker("libs/worker-hermite.js");
my_worker.onmessage = function(event){ //log(event.data);return false;
cpu_in_use--;
var complete = ((cores - cpu_in_use) / cores * 100 | 0);
progress.value = progress.innerHTML = complete;
var offset = event.data.offset; //log( event.data.data.length);
for(var i = 0; i < event.data.data.length; i += 4){
var x = offset + i; //log([ x, event.data.data[i], event.data.data[i+1],event.data.data[i+2],event.data.data[i+3], ]); return false;
data2[x] = event.data.data[i];
data2[x + 1] = event.data.data[i+1];
data2[x + 2] = event.data.data[i+2];
data2[x + 3] = event.data.data[i+3];
}
//finish
if(cpu_in_use <= 0){
console.log("hermite "+cores+" cores = "+(Math.round(Date.now() - time1)/1000)+" s");
canvas.getContext("2d").clearRect(0, 0, W, H);
canvas.getContext("2d").putImageData(img2, 0, 0);
progress.style.display='none';
if(MENU.last_menu != 'layer_resize')
DRAW.trim();
DRAW.zoom();
}
};
my_worker.postMessage([img, W, H, W2, H2, c, cores]);
}
};
}

View File

@ -118,8 +118,11 @@ function HELPER_CLASS(){
y1 = y1 + 0.5;
x2 = x2 + 0.5;
y2 = y2 + 0.5;
canvas.strokeStyle = color;
if (dashLen == undefined) dashLen = 4;
if(color != undefined)
canvas.strokeStyle = color;
else
canvas.strokeStyle = "#000000";
if(dashLen == undefined) dashLen = 4;
canvas.beginPath();
canvas.moveTo(x1, y1);
var dX = x2 - x1;
@ -255,11 +258,110 @@ function HELPER_CLASS(){
link.href = 'data:,' + fileContents;
link.click();
}
//credits: richard maloney 2006
this.darkenColor = function(color, v){
if (color.length >6) { color= color.substring(1,color.length)}
var rgb = parseInt(color, 16);
var r = Math.abs(((rgb >> 16) & 0xFF)+v); if (r>255) r=r-(r-255);
var g = Math.abs(((rgb >> 8) & 0xFF)+v); if (g>255) g=g-(g-255);
var b = Math.abs((rgb & 0xFF)+v); if (b>255) b=b-(b-255);
r = Number(r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r).toString(16);
if (r.length == 1) r = '0' + r;
g = Number(g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g).toString(16);
if (g.length == 1) g = '0' + g;
b = Number(b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b).toString(16);
if (b.length == 1) b = '0' + b;
return "#" + r + g + b;
};
//IntegraXor Web SCADA - JavaScript Number Formatter, author: KPL, KHL
this.format = function(b,a){
if(!b||isNaN(+a))return a;
var a=b.charAt(0)=="-"?-a:+a,j=a<0?a=-a:0,e=b.match(/[^\d\-\+#]/g),h=e&&e[e.length-1]||".",e=e&&e[1]&&e[0]||",",b=b.split(h),a=a.toFixed(b[1]&&b[1].length),a=+a+"",d=b[1]&&b[1].lastIndexOf("0"),c=a.split(".");
if(!c[1]||c[1]&&c[1].length<=d)
a=(+a).toFixed(d+1);
d=b[0].split(e);
b[0]=d.join("");
var f=b[0]&&b[0].indexOf("0");
if(f>-1) for(;c[0].length<b[0].length-f;)c[0]="0"+c[0];
else +c[0]==0&&(c[0]="");
a=a.split(".");a[0]=c[0];
if(c=d[1]&&d[d.length-1].length)
{for(var d=a[0],f="",k=d.length%c,g=0,i=d.length;g<i;g++)f+=d.charAt(g),!((g-k+1)%c)&&g<i-c&&(f+=e);a[0]=f;}
a[1]=b[1]&&a[1]?h+a[1]:"";
return(j?"-":"")+a[0]+a[1];
};
}
//http://www.script-tutorials.com/html5-canvas-custom-brush1/
var BezierCurveBrush = {
// inner variables
iPrevX : 0,
iPrevY : 0,
points : null,
// initialization function
init: function () { },
startCurve: function (x, y) {
this.iPrevX = x;
this.iPrevY = y;
this.points = new Array();
},
getPoint: function (iLength, a) {
var index = a.length - iLength, i;
for (i=index; i< a.length; i++) {
if (a[i]) {
return a[i];
}
}
},
draw: function (ctx, color_rgb, x, y) {
if (Math.abs(this.iPrevX - x) > 5 || Math.abs(this.iPrevY - y) > 5) {
this.points.push([x, y]);
// draw main path stroke
ctx.beginPath();
ctx.moveTo(this.iPrevX, this.iPrevY);
ctx.lineTo(x, y);
ctx.lineWidth = 1;
ctx.strokeStyle = 'rgba(' + color_rgb.r + ', ' + color_rgb.g + ', ' + color_rgb.b + ', 0.9)';
ctx.stroke();
ctx.closePath();
// draw extra strokes
ctx.strokeStyle = 'rgba(' + color_rgb.r + ', ' + color_rgb.g + ', ' + color_rgb.b + ', 0.2)';
ctx.beginPath();
var iStartPoint = this.getPoint(25, this.points);
var iFirstPoint = this.getPoint(1, this.points);
var iSecondPoint = this.getPoint(5, this.points);
ctx.moveTo(iStartPoint[0],iStartPoint[1]);
ctx.bezierCurveTo(iFirstPoint[0], iFirstPoint[1], iSecondPoint[0], iSecondPoint[1], x, y);
ctx.stroke();
ctx.closePath();
this.iPrevX = x;
this.iPrevY = y;
}
}
};
//quick access short functions
function log(object){
console.log(object);
if(typeof object != 'object')
console.log(object);
else{
var str = '[';
for(var i in object){
if(typeof object[i] == 'number')
str += Math.round(object[i]*1000)/1000+", ";
else
str += object[i]+", ";
}
str += ']';
log(str);
}
}
function round(number){
return Math.round(number);

View File

@ -26,6 +26,27 @@ function LAYER_CLASS(){
//image
var new_name = name;
//check size
var size_increased = false;
if(img.width > WIDTH || img.height > HEIGHT){
if(img.width > WIDTH)
WIDTH = img.width;
if(img.height > HEIGHT)
HEIGHT = img.height;
RATIO = WIDTH/HEIGHT;
LAYER.set_canvas_size();
size_increased = true;
}
if(LAYERS.length == 1 && CON.autosize == true && size_increased == false){
var trim_info = DRAW.trim_info(document.getElementById("Background"));
if(trim_info.left == WIDTH){
WIDTH = img.width;
HEIGHT = img.height;
RATIO = WIDTH/HEIGHT;
LAYER.set_canvas_size(false);
}
}
for(var i in LAYERS){
if(LAYERS[i].name == new_name)
new_name = 'Layer #'+(LAYERS.length+1);
@ -37,23 +58,13 @@ function LAYER_CLASS(){
opacity: 1,
});
LAYER.layer_active = LAYERS.length-1;
LAYER.layer_renew();
//check size
if(img.width > WIDTH || img.height > HEIGHT){
if(img.width > WIDTH)
WIDTH = img.width;
if(img.height > HEIGHT)
HEIGHT = img.height;
RATIO = WIDTH/HEIGHT;
LAYER.set_canvas_size();
CON.calc_preview_auto();
}
document.getElementById(new_name).getContext("2d").globalAlpha = 1;
document.getElementById(new_name).getContext('2d').drawImage(img, 0, 0);
LAYER.layer_renew();
if(LAYERS.length <= 2 && CON.autosize == true)
DRAW.trim();
/*if(LAYERS.length <= 2 && CON.autosize == true && size_increased == false){
DRAW.trim(undefined, undefined, true);
}*/
DRAW.zoom();
}
}
@ -68,7 +79,6 @@ function LAYER_CLASS(){
document.getElementById('canvas_more').appendChild(new_canvas);
document.getElementById(canvas_id).width = WIDTH;
document.getElementById(canvas_id).height = HEIGHT;
document.getElementById(canvas_id).getContext("2d").fillStyle = "rgba(255, 255, 255, 0.5)";
document.getElementById(canvas_id).getContext("2d").mozImageSmoothingEnabled = false;
document.getElementById(canvas_id).getContext("2d").webkitImageSmoothingEnabled = false;
//document.getElementById(canvas_id).getContext("2d").scale(ZOOM/100, ZOOM/100);
@ -209,15 +219,19 @@ function LAYER_CLASS(){
document.getElementById('info').innerHTML = html;
}
this.set_canvas_size = function(){
this.set_canvas_size = function(repaint){
var W = round(WIDTH);
var H = round(W / RATIO);
this.resize_canvas("canvas_back");
DRAW.draw_background(canvas_back);
DRAW.draw_background(canvas_back, WIDTH, HEIGHT);
this.resize_canvas("canvas_front", false);
for(i in LAYERS)
this.resize_canvas(LAYERS[i].name, true);
for(i in LAYERS){
if(repaint === false)
this.resize_canvas(LAYERS[i].name, false);
else
this.resize_canvas(LAYERS[i].name, true);
}
document.getElementById('resize-w').style.marginLeft = (106+W)+"px";
document.getElementById('resize-w').style.marginTop = (1+H/2)+"px";

View File

@ -1,23 +1,25 @@
/*
TODO:
git
Hermite
http://stackoverflow.com/questions/2303690/resizing-an-image-in-an-html5-canvas
http://bvdwolf.home.xs4all.nl/main/foto/down_sample/down_sample.htm
Differences
*/
var MAIN = new MAIN_CLASS();
var POP = new popup(WIDTH, HEIGHT);
document.onload = MAIN.init(true);
function MAIN_CLASS(){
this.grid = false;
this.TRANSPARENCY = true;
var LAYERS_ARCHIVE = [{}, {}, {}];
var LAYERS_ARCHIVE_REDO = {};
var LAYERS_ARCHIVE = [{}, {}, {}];
var undo_level = 0;
this.init = function(first_load){
if(first_load===true)
if(first_load===true){
TOOLS.draw_helpers();
POP.height_mini = Math.round(POP.width_mini * HEIGHT / WIDTH);
}
CON.autosize = true;
TOOLS.EXIF = false;
TOOLS.select_data = false;
@ -27,13 +29,18 @@ function MAIN_CLASS(){
canvas_main.clearRect(0, 0, WIDTH, HEIGHT);
LAYER.layer_add("Background");
LAYER.set_canvas_size();
DRAW.draw_background(canvas_back);
DRAW.draw_background(canvas_back, WIDTH, HEIGHT);
document.getElementById("main_colour").style.backgroundColor = COLOUR;
document.getElementById("canvas_preview").width = DRAW.PREVIEW_SIZE.w;
document.getElementById("canvas_preview").height = DRAW.PREVIEW_SIZE.h;
var color_rgb = HELPER.hex2rgb(COLOUR);
document.getElementById("rgb_r").value = color_rgb.r;
document.getElementById("rgb_g").value = color_rgb.g;
document.getElementById("rgb_b").value = color_rgb.b;
document.getElementById("rgb_a").value = ALPHA;
DRAW.redraw_preview();
}
this.save_state = function(){ //log('save...');
this.save_state = function(){
undo_level = 0;
j = 0;
@ -49,12 +56,12 @@ function MAIN_CLASS(){
for(var i in LAYERS)
LAYERS_ARCHIVE[j].data[LAYERS[i].name] = document.getElementById(LAYERS[i].name).getContext("2d").getImageData(0, 0, WIDTH, HEIGHT);
}
//supports 3 levels undo system
this.undo = function(){ //log('loading...');
//supports 3 levels undo system - more levels requires more memory - max 1 gb?
this.undo = function(){
if(LAYERS_ARCHIVE.length == 0) return false;
j = undo_level;
undo_level++;
if(LAYERS_ARCHIVE[j] == undefined) return false;
if(LAYERS_ARCHIVE[j] == undefined || LAYERS_ARCHIVE[j].width == undefined) return false;
if(WIDTH != LAYERS_ARCHIVE[j].width || HEIGHT != LAYERS_ARCHIVE[j].height){
WIDTH = LAYERS_ARCHIVE[j].width;
HEIGHT = LAYERS_ARCHIVE[j].height;
@ -63,12 +70,6 @@ function MAIN_CLASS(){
return true; //size changed, cant undo
}
//save current state
LAYERS_ARCHIVE_REDO = {};
LAYERS_ARCHIVE_REDO.data = {};
for(var i in LAYERS)
LAYERS_ARCHIVE_REDO.data[LAYERS[i].name] = document.getElementById(LAYERS[i].name).getContext("2d").getImageData(0, 0, WIDTH, HEIGHT);
//undo
for(var i in LAYERS){
if(LAYERS_ARCHIVE[j].data[LAYERS[i].name] != undefined)
@ -76,13 +77,6 @@ function MAIN_CLASS(){
}
DRAW.zoom();
}
this.redo = function(){
if(LAYERS_ARCHIVE_REDO.data == undefined) return false;
for(var i in LAYERS){
if(LAYERS_ARCHIVE_REDO.data[LAYERS[i].name] != undefined)
document.getElementById(LAYERS[i].name).getContext("2d").putImageData(LAYERS_ARCHIVE_REDO.data[LAYERS[i].name], 0, 0);
}
}
this.load_xml = function(data){
var xml = $.parseXML(data);
w = $(xml).find("width").text();

View File

@ -2,7 +2,6 @@ var MENU = new MENU_CLASS();
function MENU_CLASS(){
this.last_menu = '';
var PASTE_DATA = false;
this.do_menu = function(name){
@ -12,8 +11,29 @@ function MENU_CLASS(){
//new
if(name == 'file_new'){
ZOOM = 100;
MAIN.init();
//ZOOM = 100;
//MAIN.init();
POP.add({name: "width", title: "Width:", value: WIDTH, });
POP.add({name: "height", title: "Height:", value: HEIGHT, });
POP.add({name: "transparency", title: "Transparent:", values: ['Yes', 'No'],});
POP.show('New file...', function(response){
var width = parseInt(response.width);
var height = parseInt(response.height);
var transparency = response.transparency;
if(response.transparency == 'Yes')
MAIN.TRANSPARENCY = true;
else
MAIN.TRANSPARENCY = false;
//DRAW.draw_background(canvas_back, WIDTH, HEIGHT);
ZOOM = 100;
WIDTH = width;
HEIGHT = height;
RATIO = WIDTH/HEIGHT;
MAIN.init();
});
}
//open
else if(name == 'file_open'){
@ -37,10 +57,6 @@ function MENU_CLASS(){
else if(name == 'edit_undo'){
MAIN.undo();
}
//redo
else if(name == 'edit_redo'){
MAIN.redo();
}
//cut
else if(name == 'edit_cut'){
MAIN.save_state();
@ -81,11 +97,23 @@ function MENU_CLASS(){
//===== Image ==========================================================
//information
else if(name == 'image_information'){
var colors = TOOLS.unique_colors_count(canvas_active(true));
colors = HELPER.format("#,##0.####", colors);
POP.add({title: "Width:", value: WIDTH, });
POP.add({title: "Height:", value: HEIGHT, });
POP.add({title: "Unique colors:", value: colors, });
//exif
for(var i in TOOLS.EXIF)
POP.add({title: i+":", value: TOOLS.EXIF[i], });
POP.show('Information', '');
}
//size
else if(name == 'image_size'){
POP.add({name: "width", title: "Enter width:", value: WIDTH, });
POP.add({name: "height", title: "Enter height:", value: HEIGHT, });
POP.add({name: "transparency", title: "Transparent:", values: ['Yes', 'No'],});
POP.add({name: "width", title: "Width:", value: WIDTH, });
POP.add({name: "height", title: "Height:", value: HEIGHT, });
POP.show('Attributes', this.resize_custom);
}
//trim
@ -117,29 +145,17 @@ function MENU_CLASS(){
}
}
//resize
else if(name == 'image_resize'){
POP.add({name: "width", title: "Enter new width:", value: WIDTH,});
POP.add({name: "height",title: "Enter new height:", value: HEIGHT});
POP.add({name: "mode", title: "Mode:", values: ["Resample - Lanczos", "Resize"],});
POP.show('Resize', this.resize_layer);
}
else if(name == 'image_resize')
MENU.resize_box();
//rotate left
else if(name == 'image_rotate_left'){
MAIN.save_state();
MENU.rotate_resize_doc(270, WIDTH, HEIGHT);
for(var i in LAYERS){
var layer = document.getElementById(LAYERS[i].name).getContext("2d");
MENU.rotate_layer({angle: 270}, layer, WIDTH, HEIGHT);
}
MENU.rotate_layer({angle: 270}, canvas_active(), WIDTH, HEIGHT);
}
//rotate right
else if(name == 'image_rotate_right'){
MAIN.save_state();
MENU.rotate_resize_doc(90, WIDTH, HEIGHT);
for(var i in LAYERS){
var layer = document.getElementById(LAYERS[i].name).getContext("2d");
MENU.rotate_layer({angle: 90}, layer, WIDTH, HEIGHT);
}
MENU.rotate_layer({angle: 90}, canvas_active(), WIDTH, HEIGHT);
}
//rotate
else if(name == 'image_rotate'){
@ -147,10 +163,7 @@ function MENU_CLASS(){
POP.show('Rotate', function(response){
MAIN.save_state();
MENU.rotate_resize_doc(response.angle, WIDTH, HEIGHT);
for(var i in LAYERS){
var layer = document.getElementById(LAYERS[i].name).getContext("2d");
MENU.rotate_layer(response, layer, WIDTH, HEIGHT);
}
MENU.rotate_layer(response, canvas_active(), WIDTH, HEIGHT);
},
function(response, canvas_preview, w, h){
MENU.rotate_layer(response, canvas_preview, w, h);
@ -159,40 +172,36 @@ function MENU_CLASS(){
//vertical flip
else if(name == 'image_vflip'){
MAIN.save_state();
for(var i in LAYERS){
var layer = document.getElementById(LAYERS[i].name).getContext("2d");
var tempCanvas = document.createElement("canvas");
var tempCtx = tempCanvas.getContext("2d");
tempCanvas.width = WIDTH;
tempCanvas.height = HEIGHT;
tempCtx.drawImage(document.getElementById(LAYERS[i].name), 0, 0, WIDTH, HEIGHT);
//flip
layer.clearRect(0, 0, WIDTH, HEIGHT);
layer.save();
layer.scale(-1, 1);
layer.drawImage(tempCanvas, -WIDTH, 0);
layer.restore();
}
var tempCanvas = document.createElement("canvas");
var tempCtx = tempCanvas.getContext("2d");
tempCanvas.width = WIDTH;
tempCanvas.height = HEIGHT;
tempCtx.drawImage(canvas_active(true), 0, 0, WIDTH, HEIGHT);
//flip
canvas_active().clearRect(0, 0, WIDTH, HEIGHT);
canvas_active().save();
canvas_active().scale(-1, 1);
canvas_active().drawImage(tempCanvas, -WIDTH, 0);
canvas_active().restore();
}
//horizontal flip
else if(name == 'image_hflip'){
MAIN.save_state();
for(var i in LAYERS){
var layer = document.getElementById(LAYERS[i].name).getContext("2d");
var tempCanvas = document.createElement("canvas");
var tempCtx = tempCanvas.getContext("2d");
tempCanvas.width = WIDTH;
tempCanvas.height = HEIGHT;
tempCtx.drawImage(document.getElementById(LAYERS[i].name), 0, 0, WIDTH, HEIGHT);
//flip
layer.clearRect(0, 0, WIDTH, HEIGHT);
layer.save();
layer.scale(1, -1);
layer.drawImage(tempCanvas, 0, -HEIGHT);
layer.restore();
}
var tempCanvas = document.createElement("canvas");
var tempCtx = tempCanvas.getContext("2d");
tempCanvas.width = WIDTH;
tempCanvas.height = HEIGHT;
tempCtx.drawImage(canvas_active(true), 0, 0, WIDTH, HEIGHT);
//flip
canvas_active().clearRect(0, 0, WIDTH, HEIGHT);
canvas_active().save();
canvas_active().scale(1, -1);
canvas_active().drawImage(tempCanvas, 0, -HEIGHT);
canvas_active().restore();
}
//histogram
else if(name == 'image_histogram'){
TOOLS.histogram();
}
//color corrections
else if(name == 'image_colors'){
@ -207,27 +216,24 @@ function MENU_CLASS(){
POP.show('Brightness Contrast', function(user_response){
MAIN.save_state();
for(var i in LAYERS){
var layer = document.getElementById(LAYERS[i].name).getContext("2d");
var param1 = parseInt(user_response.param1);
var param2 = parseInt(user_response.param2);
var param_red = parseInt(user_response.param_red);
var param_green = parseInt(user_response.param_green);
var param_blue = parseInt(user_response.param_blue);
var param_h = parseInt(user_response.param_h);
var param_s = parseInt(user_response.param_s);
var param_l = parseInt(user_response.param_l);
var imageData = layer.getImageData(0, 0, WIDTH, HEIGHT);
//Brightness/Contrast
var filtered = ImageFilters.BrightnessContrastPhotoshop(imageData, param1, param2);
//RGB corrections
var filtered = ImageFilters.ColorTransformFilter(filtered, 1, 1, 1, 1, param_red, param_green, param_blue, 1);
//hue/saturation/luminance
var filtered = ImageFilters.HSLAdjustment(filtered, param_h, param_s, param_l);
layer.putImageData(filtered, 0, 0);
DRAW.zoom();
}
var param1 = parseInt(user_response.param1);
var param2 = parseInt(user_response.param2);
var param_red = parseInt(user_response.param_red);
var param_green = parseInt(user_response.param_green);
var param_blue = parseInt(user_response.param_blue);
var param_h = parseInt(user_response.param_h);
var param_s = parseInt(user_response.param_s);
var param_l = parseInt(user_response.param_l);
var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT);
//Brightness/Contrast
var filtered = ImageFilters.BrightnessContrastPhotoshop(imageData, param1, param2);
//RGB corrections
var filtered = ImageFilters.ColorTransformFilter(filtered, 1, 1, 1, 1, param_red, param_green, param_blue, 1);
//hue/saturation/luminance
var filtered = ImageFilters.HSLAdjustment(filtered, param_h, param_s, param_l);
canvas_active().putImageData(filtered, 0, 0);
DRAW.zoom();
},
function(user_response, canvas_preview, w, h){
var param1 = parseInt(user_response.param1);
@ -249,28 +255,44 @@ function MENU_CLASS(){
canvas_preview.putImageData(filtered, 0, 0);
});
}
//auto adjust colors
else if(name == 'image_auto_adjust'){
MAIN.save_state();
DRAW.auto_adjust(canvas_active(), WIDTH, HEIGHT);
}
//enchance colors
else if(name == 'image_decrease_colors'){
POP.add({name: "param1", title: "Colors:", value: "10", range: [2, 100], });
POP.add({name: "param2", title: "Dithering:", values: ["Yes", "No"], });
POP.add({name: "param3", title: "Greyscale:", values: ["Yes", "No"], value: "No", });
POP.show('Decrease colors', function(user_response){
MAIN.save_state();
var param1 = parseInt(user_response.param1);
if(user_response.param2 == 'Yes') param2 = true; else param2 = false;
if(user_response.param3 == 'Yes') param3 = true; else param3 = false;
DRAW.decrease_colors(canvas_active(), WIDTH, HEIGHT, param1, param2, param3);
DRAW.zoom();
});
}
//negative
else if(name == 'image_negative'){
MAIN.save_state();
for(var i in LAYERS){
var layer = document.getElementById(LAYERS[i].name).getContext("2d");
if(TOOLS.select_data == false)
var imageData = layer.getImageData(0, 0, WIDTH, HEIGHT);
else
var imageData = layer.getImageData(TOOLS.select_data.x, TOOLS.select_data.y, TOOLS.select_data.w, TOOLS.select_data.h);
var pixels = imageData.data;
for (var i = 0; i < pixels.length; i += 4){
pixels[i] = 255 - pixels[i]; // red
pixels[i+1] = 255 - pixels[i+1]; // green
pixels[i+2] = 255 - pixels[i+2]; // blue
}
//save
if(TOOLS.select_data == false)
layer.putImageData(imageData, 0, 0);
else
layer.putImageData(imageData, TOOLS.select_data.x, TOOLS.select_data.y);
if(TOOLS.select_data == false)
var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT);
else
var imageData = canvas_active().getImageData(TOOLS.select_data.x, TOOLS.select_data.y, TOOLS.select_data.w, TOOLS.select_data.h);
var pixels = imageData.data;
for (var i = 0; i < pixels.length; i += 4){
pixels[i] = 255 - pixels[i]; // red
pixels[i+1] = 255 - pixels[i+1]; // green
pixels[i+2] = 255 - pixels[i+2]; // blue
}
//save
if(TOOLS.select_data == false)
canvas_active().putImageData(imageData, 0, 0);
else
canvas_active().putImageData(imageData, TOOLS.select_data.x, TOOLS.select_data.y)
}
//grid
else if(name == 'image_grid'){
@ -288,7 +310,7 @@ function MENU_CLASS(){
else{
MAIN.grid = false;
canvas_back.clearRect(0, 0, WIDTH, HEIGHT);
DRAW.draw_background(canvas_back);
DRAW.draw_background(canvas_back, WIDTH, HEIGHT);
}
}
@ -339,151 +361,52 @@ function MENU_CLASS(){
else if(name == 'layer_opacity'){
LAYER.set_alpha();
}
//color corrections
else if(name == 'layer_colors'){
POP.add({name: "param1", title: "Brightness:", value: "0", range: [-100, 100], });
POP.add({name: "param2", title: "Contrast:", value: "0", range: [-100, 100], });
POP.add({name: "param_red", title: "Red offset:", value: "0", range: [-255, 255], });
POP.add({name: "param_green", title: "Green offset:", value: "0", range: [-255, 255], });
POP.add({name: "param_blue", title: "Blue offset:", value: "0", range: [-255, 255], });
POP.add({name: "param_h", title: "Hue:", value: "0", range: [-180, 180], });
POP.add({name: "param_s", title: "Saturation:", value: "0", range: [-100, 100], });
POP.add({name: "param_l", title: "Luminance:", value: "0", range: [-100, 100], });
POP.show('Brightness Contrast', function(user_response){
MAIN.save_state();
var param1 = parseInt(user_response.param1);
var param2 = parseInt(user_response.param2);
var param_red = parseInt(user_response.param_red);
var param_green = parseInt(user_response.param_green);
var param_blue = parseInt(user_response.param_blue);
var param_h = parseInt(user_response.param_h);
var param_s = parseInt(user_response.param_s);
var param_l = parseInt(user_response.param_l);
var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT);
//Brightness/Contrast
var filtered = ImageFilters.BrightnessContrastPhotoshop(imageData, param1, param2);
//RGB corrections
var filtered = ImageFilters.ColorTransformFilter(filtered, 1, 1, 1, 1, param_red, param_green, param_blue, 1);
//hue/saturation/luminance
var filtered = ImageFilters.HSLAdjustment(filtered, param_h, param_s, param_l);
canvas_active().putImageData(filtered, 0, 0);
DRAW.zoom();
},
function(user_response, canvas_preview, w, h){
var param1 = parseInt(user_response.param1);
var param2 = parseInt(user_response.param2);
var param_red = parseInt(user_response.param_red);
var param_green = parseInt(user_response.param_green);
var param_blue = parseInt(user_response.param_blue);
var param_h = parseInt(user_response.param_h);
var param_s = parseInt(user_response.param_s);
var param_l = parseInt(user_response.param_l);
var imageData = canvas_preview.getImageData(0, 0, w, h);
//Brightness/Contrast
var filtered = ImageFilters.BrightnessContrastPhotoshop(imageData, param1, param2); //add effect
//RGB corrections
var filtered = ImageFilters.ColorTransformFilter(filtered, 1, 1, 1, 1, param_red, param_green, param_blue, 1);
//hue/saturation/luminance
var filtered = ImageFilters.HSLAdjustment(filtered, param_h, param_s, param_l);
canvas_preview.putImageData(filtered, 0, 0);
});
}
//rotate left
else if(name == 'layer_rotate_left'){
MAIN.save_state();
MENU.rotate_layer({angle: 270}, canvas_active(), WIDTH, HEIGHT);
}
//rotate right
else if(name == 'layer_rotate_right'){
MAIN.save_state();
MENU.rotate_layer({angle: 90}, canvas_active(), WIDTH, HEIGHT);
}
//rotate
else if(name == 'layer_rotate'){
POP.add({name: "angle", title: "Enter angle (0-360):", value: 90, range: [0, 360], });
POP.show('Rotate', function(response){
MAIN.save_state();
MENU.rotate_layer(response, canvas_active(), WIDTH, HEIGHT);
},
function(response, canvas_preview, w, h){
MENU.rotate_layer(response, canvas_preview, w, h);
});
}
//vertical flip
else if(name == 'layer_vflip'){
MAIN.save_state();
var tempCanvas = document.createElement("canvas");
var tempCtx = tempCanvas.getContext("2d");
tempCanvas.width = WIDTH;
tempCanvas.height = HEIGHT;
tempCtx.drawImage(canvas_active(true), 0, 0, WIDTH, HEIGHT);
//flip
canvas_active().clearRect(0, 0, WIDTH, HEIGHT);
canvas_active().save();
canvas_active().scale(-1, 1);
canvas_active().drawImage(tempCanvas, -WIDTH, 0);
canvas_active().restore();
}
//horizontal flip
else if(name == 'layer_hflip'){
MAIN.save_state();
var tempCanvas = document.createElement("canvas");
var tempCtx = tempCanvas.getContext("2d");
tempCanvas.width = WIDTH;
tempCanvas.height = HEIGHT;
tempCtx.drawImage(canvas_active(true), 0, 0, WIDTH, HEIGHT);
//flip
canvas_active().clearRect(0, 0, WIDTH, HEIGHT);
canvas_active().save();
canvas_active().scale(1, -1);
canvas_active().drawImage(tempCanvas, 0, -HEIGHT);
canvas_active().restore();
}
//trim
else if(name == 'layer_trim'){
MAIN.save_state();
DRAW.trim(LAYERS[LAYER.layer_active].name, true);
}
//resize
else if(name == 'layer_resize'){
POP.add({name: "width", title: "Enter new width:", value: WIDTH,});
POP.add({name: "height",title: "Enter new height:", value: HEIGHT});
POP.add({name: "mode", title: "Mode:", values: ["Resample - Lanczos", "Resize"],});
POP.show('Resize', this.resize_layer);
}
//negative
else if(name == 'layer_negative'){
MAIN.save_state();
if(TOOLS.select_data == false)
var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT);
else
var imageData = canvas_active().getImageData(TOOLS.select_data.x, TOOLS.select_data.y, TOOLS.select_data.w, TOOLS.select_data.h);
var pixels = imageData.data;
for (var i = 0; i < pixels.length; i += 4){
pixels[i] = 255 - pixels[i]; // red
pixels[i+1] = 255 - pixels[i+1]; // green
pixels[i+2] = 255 - pixels[i+2]; // blue
}
//save
if(TOOLS.select_data == false)
canvas_active().putImageData(imageData, 0, 0);
else
canvas_active().putImageData(imageData, TOOLS.select_data.x, TOOLS.select_data.y)
}
else if(name == 'layer_resize')
MENU.resize_box();
//clear
else if(name == 'layer_clear'){
MAIN.save_state();
canvas_active().clearRect(0, 0, WIDTH, HEIGHT);
}
//sprites
else if(name == 'layer_sprites'){
POP.add({name: "param1", title: "Offset:", value: "50", values: ["0", "10", "50", "100"] });
POP.show('Sprites', function(response){
MAIN.save_state();
var param1 = parseInt(response.param1);
TOOLS.generate_sprites(param1);
});
}
//show differences
else if(name == 'layer_differences'){
if(parseInt(LAYER.layer_active) + 1 >= LAYERS.length){
POP.add({title: "Error:", value: 'This can not be last layer', });
POP.show('Error', '');
return false;
}
POP.add({name: "param1", title: "Sensitivity:", value: "0", range: [0, 255] });
POP.show('Differences', function(response){
var param1 = parseInt(response.param1);
TOOLS.calc_differences(param1);
},
function(user_response, canvas_preview, w, h){
var param1 = parseInt(user_response.param1);
TOOLS.calc_differences(param1, canvas_preview, w, h);
});
}
//merge
else if(name == 'layer_merge_down'){
MAIN.save_state();
vlayer_active = parseInt(layer_active);
if(LAYER.layer_active + 1 > LAYERS.length){
POP.add({title: "Error:", value: 'This is last layer', });
vlayer_active = parseInt(LAYER.layer_active);
if(parseInt(LAYER.layer_active) + 1 >= LAYERS.length){
POP.add({title: "Error:", value: 'This can not be last layer', });
POP.show('Error', '');
return false;
}
@ -502,18 +425,6 @@ function MENU_CLASS(){
LAYER.layer_remove(LAYER.layer_active+1);
LAYER.layer_renew();
}
//exif
else if(name == 'image_exif'){
if(TOOLS.EXIF === false){
POP.add({title: "Error:", value: 'EXIF info not found.', });
POP.show('EXIF info', '');
}
else{
for(var i in TOOLS.EXIF)
POP.add({title: i+":", value: TOOLS.EXIF[i], });
POP.show('EXIF info', '');
}
}
//flatten all
else if(name == 'layer_flatten'){
MAIN.save_state();
@ -521,7 +432,7 @@ function MENU_CLASS(){
tmp_data = document.createElement("canvas");
tmp_data.width = WIDTH;
tmp_data.height = HEIGHT;
for(var i=LAYERS.length - 1; i > 0; i--){
for(var i=1; i < LAYERS.length; i++){
//copy
LAYER.layer_active = i;
tmp_data.getContext("2d").clearRect(0, 0, WIDTH, HEIGHT);
@ -530,7 +441,8 @@ function MENU_CLASS(){
//paste
LAYER.layer_active = 0;
canvas_active().drawImage(tmp_data, 0, 0);
}
for(var i=LAYERS.length - 1; i > 0; i--){
//delete layer
LAYER.layer_active = i;
LAYER.layer_remove(LAYER.layer_active);
@ -541,8 +453,19 @@ function MENU_CLASS(){
//===== Effects ========================================================
else if(name == 'effects_bw'){
MAIN.save_state();
DRAW.effect_bw(canvas_active(), WIDTH, HEIGHT);
POP.add({name: "param1", title: "Level:", value: "125", range: [0, 255], });
POP.show('Black and White', function(user_response){
MAIN.save_state();
var param1 = parseInt(user_response.param1);
DRAW.effect_bw(canvas_active(), WIDTH, HEIGHT, param1);
DRAW.zoom();
},
function(user_response, canvas_preview, w, h){
var param1 = parseInt(user_response.param1);
DRAW.effect_bw(canvas_preview, w, h, param1);
});
}
else if(name == 'effects_BoxBlur'){
POP.add({name: "param1", title: "H Radius:", value: "3", range: [1, 20], });
@ -604,6 +527,46 @@ function MENU_CLASS(){
canvas_preview.putImageData(filtered, 0, 0);
});
}
else if(name == 'effects_zoomblur'){
POP.add({name: "param1", title: "Strength:", value: "0.3", range: [0, 1], step: 0.01, });
POP.add({name: "param2", title: "Center x:", value: round(WIDTH/2), range: [0, WIDTH], });
POP.add({name: "param3", title: "Center y:", value: round(HEIGHT/2), range: [0, HEIGHT], });
POP.show('Blur-Zoom', function(user_response){
MAIN.save_state();
var param1 = parseFloat(user_response.param1);
var param2 = parseInt(user_response.param2);
var param3 = parseInt(user_response.param3);
var filter = fx.canvas();
var texture = filter.texture(canvas_active(true));
filter.draw(texture).zoomBlur(param2, param3, param1).update(); //effect
canvas_active().clearRect(0, 0, WIDTH, HEIGHT);
canvas_active().drawImage(filter, 0, 0);
DRAW.zoom();
},
function(user_response, canvas_preview, w, h){
var param1 = parseFloat(user_response.param1);
var param2 = parseInt(user_response.param2);
var param3 = parseInt(user_response.param3);
//recalc param by size
param2 = param2 / WIDTH * w;
param3 = param3 / HEIGHT * h;
var filter = fx.canvas();
var texture = filter.texture(canvas_preview.getImageData(0, 0, w, h));
filter.draw(texture).zoomBlur(param2, param3, param1).update(); //effect
canvas_preview.drawImage(filter, 0, 0);
//draw circle
canvas_preview.beginPath();
canvas_preview.strokeStyle = "#ff0000";
canvas_preview.lineWidth = 1;
canvas_preview.beginPath();
canvas_preview.arc(param2, param3, 5, 0,Math.PI*2,true);
canvas_preview.stroke();
});
}
else if(name == 'effects_BrightnessContrast'){
POP.add({name: "param1", title: "Brightness:", value: "0", range: [-100, 100], });
POP.add({name: "param2", title: "Contrast:", value: "0", range: [-100, 100], });
@ -657,17 +620,13 @@ function MENU_CLASS(){
});
}
else if(name == 'effects_Channels'){
POP.add({name: "param1", title: "Red:", value: "1", range: [0, 1], });
POP.add({name: "param2", title: "Green:", value: "0", range: [0, 1], });
POP.add({name: "param3", title: "Blue:", value: "0", range: [0, 1], });
POP.add({name: "param1", title: "Channel:", values: ["Red", "Green", "Blue"],});
POP.show('Channels', function(user_response){
MAIN.save_state();
var param1 = parseInt(user_response.param1);
var param2 = parseInt(user_response.param2);
var param3 = parseInt(user_response.param3);
var channel = 1;
if(param2 == 1) channel = 2;
if(param3 == 1) channel = 3;
var param1 = user_response.param1;
if(param1 == "Red") channel = 1;
else if(param1 == "Green") channel = 2;
else if(param1 == "Blue") channel = 3;
var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT);
var filtered = ImageFilters.Channels(imageData, channel); //add effect
@ -675,22 +634,16 @@ function MENU_CLASS(){
DRAW.zoom();
},
function(user_response, canvas_preview, w, h){
var param1 = parseInt(user_response.param1);
var param2 = parseInt(user_response.param2);
var param3 = parseInt(user_response.param3);
var channel = 1;
if(param2 == 1) channel = 2;
if(param3 == 1) channel = 3;
var param1 = user_response.param1;
if(param1 == "Red") channel = 1;
else if(param1 == "Green") channel = 2;
else if(param1 == "Blue") channel = 3;
var imageData = canvas_preview.getImageData(0, 0, w, h);
var filtered = ImageFilters.Channels(imageData, channel); //add effect
canvas_preview.putImageData(filtered, 0, 0);
});
}
else if(name == 'effects_ColorTransformFilter'){
/*POP.add({name: "param1", title: "Red multiplier:", value: "1", range: [0, 5], });
POP.add({name: "param2", title: "Green multiplier:", value: "1", range: [0, 5], });
POP.add({name: "param3", title: "Blue multiplier:", value: "1", range: [0, 5], });
POP.add({name: "param4", title: "Alpha multiplier:", value: "1", range: [0, 5], });*/
POP.add({name: "param5", title: "Red offset:", value: "0", range: [-255, 255], });
POP.add({name: "param6", title: "Green offset:", value: "0", range: [-255, 255], });
POP.add({name: "param7", title: "Blue offset:", value: "0", range: [-255, 255], });
@ -717,6 +670,57 @@ function MENU_CLASS(){
canvas_preview.putImageData(filtered, 0, 0);
});
}
else if(name == 'effects_colorize'){
var colorize_data;
POP.add({name: "param1", title: "Power:", value: "3", range: [1, 10], });
POP.add({name: "param2", title: "Limit:", value: "30", range: [10, 200], });
POP.add({name: "param3", title: "Dithering:", values: ["Yes", "No"], });
POP.add({title: "Shortcut:", value: "C", });
POP.preview_in_main = true;
POP.show('Auto colorize', function(user_response){
MAIN.save_state();
var param1 = parseInt(user_response.param1);
var param2 = parseInt(user_response.param2);
if(user_response.param3 == 'Yes') param3 = true; else param3 = false;
DRAW.colorize(canvas_active(), WIDTH, HEIGHT, param1, param2, param3, colorize_data);
DRAW.zoom();
canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
},
function(user_response){
var param1 = parseInt(user_response.param1);
var param2 = parseInt(user_response.param2);
if(user_response.param3 == 'Yes') param3 = true; else param3 = false;
colorize_data = DRAW.colorize(canvas_preview, WIDTH, HEIGHT, param1, param2, param3, true);
canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
canvas_front.drawImage(canvas_active(true), 0, 0);
DRAW.colorize(canvas_front, WIDTH, HEIGHT, param1, param2, param3, colorize_data);
});
}
else if(name == 'effects_denoise'){
POP.add({name: "param1", title: "Exponent:", value: "20", range: [0, 50], });
POP.show('Denoise', function(user_response){
MAIN.save_state();
var param1 = parseFloat(user_response.param1);
var filter = fx.canvas();
var texture = filter.texture(canvas_active(true));
filter.draw(texture).denoise(param1).update(); //effect
canvas_active().clearRect(0, 0, WIDTH, HEIGHT);
canvas_active().drawImage(filter, 0, 0);
DRAW.zoom();
},
function(user_response, canvas_preview, w, h){
var param1 = parseFloat(user_response.param1);
var filter = fx.canvas();
var texture = filter.texture(canvas_preview.getImageData(0, 0, w, h));
filter.draw(texture).denoise(param1).update(); //effect
canvas_preview.drawImage(filter, 0, 0);
});
}
else if(name == 'effects_Desaturate'){
MAIN.save_state();
var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT);
@ -872,6 +876,68 @@ function MENU_CLASS(){
canvas_preview.putImageData(filtered, 0, 0);
});
}
else if(name == 'effects_perspective'){
POP.add({name: "param1", title: "X1:", value: WIDTH/4, range: [0, WIDTH], });
POP.add({name: "param2", title: "Y1:", value: "0", range: [0, HEIGHT], });
POP.add({name: "param3", title: "X2:", value: WIDTH*3/4, range: [0, WIDTH], });
POP.add({name: "param4", title: "Y2:", value: "0", range: [0, HEIGHT], });
POP.add({name: "param5", title: "X3:", value: WIDTH, range: [0, WIDTH], });
POP.add({name: "param6", title: "Y3:", value: HEIGHT, range: [0, HEIGHT], });
POP.add({name: "param7", title: "X4:", value: "0", range: [0, WIDTH], });
POP.add({name: "param8", title: "Y4:", value: HEIGHT, range: [0, HEIGHT], });
POP.show('Blur-Zoom', function(user_response){
MAIN.save_state();
var param1 = parseInt(user_response.param1);
var param2 = parseInt(user_response.param2);
var param3 = parseInt(user_response.param3);
var param4 = parseInt(user_response.param4);
var param5 = parseInt(user_response.param5);
var param6 = parseInt(user_response.param6);
var param7 = parseInt(user_response.param7);
var param8 = parseInt(user_response.param8);
var filter = fx.canvas();
var texture = filter.texture(canvas_active(true));
filter.draw(texture).perspective([0,0,WIDTH,0,WIDTH,HEIGHT,0,HEIGHT], [param1,param2,param3,param4,param5,param6,param7,param8]).update(); //effect
canvas_active().clearRect(0, 0, WIDTH, HEIGHT);
canvas_active().drawImage(filter, 0, 0);
DRAW.zoom();
},
function(user_response, canvas_preview, w, h){
var param1 = parseInt(user_response.param1);
var param2 = parseInt(user_response.param2);
var param3 = parseInt(user_response.param3);
var param4 = parseInt(user_response.param4);
var param5 = parseInt(user_response.param5);
var param6 = parseInt(user_response.param6);
var param7 = parseInt(user_response.param7);
var param8 = parseInt(user_response.param8);
param1 = param1 / WIDTH * w;
param2 = param2 / HEIGHT * h;
param3 = param3 / WIDTH * w;
param4 = param4 / HEIGHT * h;
param5 = param5 / WIDTH * w;
param6 = param6 / HEIGHT * h;
param7 = param7 / WIDTH * w;
param8 = param8 / HEIGHT * h;
var filter = fx.canvas();
var texture = filter.texture(canvas_preview.getImageData(0, 0, w, h));
canvas_preview.clearRect(0, 0, w, h);
filter.draw(texture).perspective([0,0,w,0,w,h,0,h], [param1,param2,param3,param4,param5,param6,param7,param8]).update(); //effect
canvas_preview.drawImage(filter, 0, 0);
//draw circle
/*canvas_preview.beginPath();
canvas_preview.strokeStyle = "#ff0000";
canvas_preview.lineWidth = 1;
canvas_preview.beginPath();
canvas_preview.arc(param2, param3, 5, 0,Math.PI*2,true);
canvas_preview.stroke();*/
});
}
else if(name == 'effects_Posterize'){
POP.add({name: "param1", title: "Levels:", value: "8", range: [2, 32], });
POP.show('Posterize', function(user_response){
@ -993,29 +1059,64 @@ function MENU_CLASS(){
canvas_preview.stroke();
});
}
else if(name == 'effects_vignette'){
POP.add({name: "param1", title: "Size:", value: "0.5", range: [0, 1], step: 0.01, });
POP.add({name: "param2", title: "Amount:", value: "0.5", range: [0, 1], step: 0.01, });
POP.show('Vignette', function(user_response){
MAIN.save_state();
var param1 = parseFloat(user_response.param1);
var param2 = parseFloat(user_response.param2);
var filter = fx.canvas();
var texture = filter.texture(canvas_active(true));
filter.draw(texture).vignette(param1, param2).update(); //effect
canvas_active().clearRect(0, 0, WIDTH, HEIGHT);
canvas_active().drawImage(filter, 0, 0);
DRAW.zoom();
},
function(user_response, canvas_preview, w, h){
var param1 = parseFloat(user_response.param1);
var param2 = parseFloat(user_response.param2);
var filter = fx.canvas();
var texture = filter.texture(canvas_preview.getImageData(0, 0, w, h));
filter.draw(texture).vignette(param1, param2).update(); //effect
canvas_preview.drawImage(filter, 0, 0);
});
}
//===== Help ===========================================================
//shortcuts
else if(name == 'help_shortcuts'){
POP.add({title: "Del:", value: 'Delete selection', });
POP.add({title: "G:", value: 'Grid on/off', });
POP.add({title: "L:", value: 'Rotate left', });
POP.add({title: "O:", value: 'Open file(s)', });
POP.add({title: "R:", value: 'Rotate right', });
POP.add({title: "S:", value: 'Save', });
POP.add({title: "T:", value: 'Trim', });
POP.add({title: "CTRL + Z:", value: 'Undo', });
POP.add({title: "CTRL + A:", value: 'Select all', });
POP.add({title: "CTRL + X:", value: 'Cut', });
POP.add({title: "CTRL + C:", value: 'Copy', });
POP.add({title: "CTRL + V:", value: 'Paste', });
POP.add({title: "Arrow keys:", value: 'Move active layer by 10px', });
POP.add({title: "CTRL + Arrow keys:", value: 'Move active layer by 50px', });
POP.add({title: "SHIFT + Arrow keys:",value: 'Move active layer by 1px', });
POP.add({title: "Drag & Drop:", value: 'Imports images/xml data', });
POP.add({title: "C", value: 'Colorize', });
POP.add({title: "Del", value: 'Delete selection', });
POP.add({title: "F", value: 'Aut oadjust colors', });
POP.add({title: "G", value: 'Grid on/off', });
POP.add({title: "L", value: 'Rotate left', });
POP.add({title: "O", value: 'Open file(s)', });
POP.add({title: "R", value: 'Resize', });
POP.add({title: "S", value: 'Save', });
POP.add({title: "T", value: 'Trim', });
POP.add({title: "-", value: 'Zoom out', });
POP.add({title: "+", value: 'Zoom in', });
POP.add({title: "CTRL + Z", value: 'Undo', });
POP.add({title: "CTRL + A", value: 'Select all', });
POP.add({title: "CTRL + X", value: 'Cut', });
POP.add({title: "CTRL + C", value: 'Copy', });
POP.add({title: "CTRL + V", value: 'Paste', });
POP.add({title: "Arrow keys", value: 'Move active layer by 10px', });
POP.add({title: "CTRL + Arrow keys", value: 'Move active layer by 50px', });
POP.add({title: "SHIFT + Arrow keys",value: 'Move active layer by 1px', });
POP.add({title: "Drag & Drop", value: 'Imports images/xml data', });
POP.show('Keyboard Shortcuts', '');
}
//credits
else if(name == 'help_credits'){
for(var i in CREDITS)
POP.add({title: CREDITS[i].title, html: '<a href="'+CREDITS[i].link+'">'+CREDITS[i].name+'</a>', });
POP.show('Credits', '');
}
//about
else if(name == 'help_about'){
POP.add({title: "Name:", value: "miniPaint "+VERSION, });
@ -1039,13 +1140,6 @@ function MENU_CLASS(){
RATIO = WIDTH/HEIGHT;
LAYER.set_canvas_size();
}
else{
if(user_response.transparency == 'Yes')
MAIN.TRANSPARENCY = true;
else
MAIN.TRANSPARENCY = false;
DRAW.draw_background(canvas_back);
}
}
//prepare rotation - increase doc dimensions if needed
this.rotate_resize_doc = function(angle, w, h){
@ -1125,42 +1219,69 @@ function MENU_CLASS(){
canvas_active().drawImage(PASTE_DATA, 0, 0);
LAYER.layer_renew();
}
this.resize_box = function(){
POP.add({name: "width", title: "Enter new width:", value: WIDTH,});
POP.add({name: "height",title: "Enter new height:", value: HEIGHT});
POP.add({name: "mode", title: "Mode:", value: "Resample - Hermite", values: ["Resize", "Resample - Hermite"],});
POP.add({name: "ratio",title: "Preserve ratio:", values: ["Yes", "No"]});
POP.add({name: "preblur",title: "Pre-Blur:", values: ["Yes", "No"], value: "No", });
POP.add({name: "sharpen",title: "Apply sharpen:", values: ["Yes", "No"], value: "No", });
POP.show('Resize', MENU.resize_layer);
}
this.resize_layer = function(user_response){
MAIN.save_state();
var width = parseInt(user_response.width);
var height = parseInt(user_response.height);
var ratio_mode = user_response.ratio;
var preblur = user_response.preblur;
var sharpen = user_response.sharpen;
if(isNaN(width) || width<1) return false;
if(isNaN(height) || height<1) return false;
if(user_response.mode == "Resample - Lanczos"){
var trim_details = DRAW.trim(LAYERS[LAYER.layer_active].name); //trim
//if increasing size - use simple way - its good enough
if(width > WIDTH || height > HEIGHT)
user_response.mode = "Resize";
var new_w = WIDTH - trim_details.left - trim_details.right;
var new_h = HEIGHT - trim_details.top - trim_details.bottom;
var ratio_new = new_w/new_h;
if(width / height > RATIO)
width = round(height * ratio_new);
//anti-artifacting?
if(preblur == 'Yes'){
var ratio_w = WIDTH / width;
var ratio_h = HEIGHT / height;
if(ratio_mode == 'Yes')
var ratio_avg = Math.max(ratio_w, ratio_h);
else
height = round(width / ratio_new);
if(width >= new_w){
LAYER.resize_canvas(LAYERS[LAYER.layer_active].name, true);
DRAW.zoom();
return false;
var ratio_avg = Math.min(ratio_w, ratio_h);
var power = ratio_avg * 0.3;
if(power > 0.6){
var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT);
var filtered = ImageFilters.GaussianBlur(imageData, power); //add effect
canvas_active().putImageData(filtered, 0, 0);
}
POP.hide();
POP.add({title: "Status:", value: 'Resizing...', });
POP.show('Status', '');
//resample using lanczos-2
DRAW.thumbnailer(canvas_active(true), width, 3);
}
else{
//Hermite - good and fast
if(user_response.mode == "Resample - Hermite"){
if(ratio_mode == 'Yes'){
if(width / height > RATIO)
width = Math.round(height * RATIO);
else
height = Math.round(width / RATIO);
}
if(width == WIDTH && height == HEIGHT) return false;
if(width > WIDTH || height > HEIGHT) return false;
DRAW.resample_hermite(canvas_active(true), WIDTH, HEIGHT, width, height);
if(MENU.last_menu != 'layer_resize')
DRAW.trim();
DRAW.zoom();
}
//simple resize
else if(user_response.mode == "Resize"){
//simple resize - FAST
if(width / height > RATIO)
width = height * RATIO;
else
height = width / RATIO;
if(ratio_mode == 'Yes'){
if(width / height > RATIO)
width = round(height * RATIO);
else
height = round(width / RATIO);
}
tmp_data = document.createElement("canvas");
tmp_data.width = WIDTH;
@ -1178,10 +1299,16 @@ function MENU_CLASS(){
LAYER.set_canvas_size();
canvas_active().drawImage(tmp_data, 0, 0, width, height);
}
if(MENU.last_menu == 'image_resize')
if(MENU.last_menu != 'layer_resize')
DRAW.trim();
DRAW.zoom();
}
//sharpen?
if(sharpen == 'Yes'){
var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT);
var filtered = ImageFilters.Sharpen(imageData, 1); //add effect
canvas_active().putImageData(filtered, 0, 0);
}
}
this.save = function(user_response){
fname = user_response.name;

View File

@ -7,31 +7,36 @@ POP.add({title: 'title:', function: 'custom_function'});
POP.show('title', main_handler, 'preview_handler', 'onload_handler');
*/
var POP = new popup();
function popup(WIDTH, HEIGHT){
function popup(){
this.active = false;
this.handler = '';
this.preview = false;
this.onload = false;
var WIDTH = WIDTH;
var HEIGHT = HEIGHT;
this.width_mini = 195;
this.height_mini = 195;
this.preview_in_main = false;
var parameters = [];
var width_mini = 195;
var height_mini = Math.round(width_mini * HEIGHT / WIDTH);
var layer_active_small = document.createElement("canvas");
var layer_active_small_ctx = layer_active_small.getContext("2d");
this.constructor = new function(){
var dim = HELPER.get_dimensions();
popup = document.getElementById('popup');
popup.style.top = 150+'px';
popup.style.left = Math.round(dim[0]/2)+'px';
}
//add parameter
this.add = function(object){
if(this.active == true){
parameters = [];
this.active = false;
}
parameters.push(object);
}
//show popup window
this.show = function(title, handler, preview_handler, onload_handler){
if(this.active == true){
this.hide();
return false;
}
this.active = true;
this.handler = handler;
if(preview_handler != undefined)
@ -41,7 +46,12 @@ function popup(WIDTH, HEIGHT){
var html = '';
var can_be_canceled = false;
html += '<h2>'+title+'</h2>';
var dim = HELPER.get_dimensions();
popup = document.getElementById('popup');
popup.style.top = 150+'px';
popup.style.left = Math.round(dim[0]/2)+'px';
html += '<h2 id="popup_drag">'+title+'</h2>';
html += '<table style="width:99%;">';
for(var i in parameters){
var parameter = parameters[i];
@ -49,10 +59,53 @@ function popup(WIDTH, HEIGHT){
html += '<td style="font-weight:bold;padding-right:3px;width:130px;">'+parameter.title+'</td>';
if(parameter.name != undefined){
can_be_canceled = true;
if(parameter.value != undefined){
var colspan = 1;
if(parameter.range != undefined)
colspan = 2;
if(parameter.values != undefined){
var onchange = '';
if(parameter.onchange != undefined)
onchange = ' onchange="'+parameter.onchange+';" ';
if(parameter.values.length > 10 || parameter.type == 'select'){
//drop down
if(onchange == '' && preview_handler != undefined)
onchange = ' onchange="POP.view();" ';
html += '<td colspan="2"><select '+onchange+' style="font-size:12px;" id="pop_data_'+parameter.name+'">';
var k = 0;
for(var j in parameter.values){
var sel = '';
if(parameter.value == parameter.values[j])
sel = 'selected="selected"';
if(parameter.value == undefined && k == 0)
sel = 'selected="selected"';
html += '<option '+sel+' name="'+parameter.values[j]+'">'+parameter.values[j]+'</option>';
k++;
}
html += '</select></td>';
}
else{
//radio
html += '<td colspan="2">';
if(parameter.values.length > 2)
html += '<div class="group">';
var k = 0;
for(var j in parameter.values){
var ch = '';
if(parameter.value == parameter.values[j])
ch = 'checked="checked"';
if(parameter.value == undefined && k == 0)
ch = 'checked="checked"';
if(onchange == '' && preview_handler != undefined)
onchange = ' onchange="POP.view();" ';
html += '<input type="radio" '+onchange+' '+ch+' name="'+parameter.name+'" id="pop_data_'+parameter.name+"_poptmp"+j+'" value="'+parameter.values[j]+'">';
html += '<label style="margin-right:20px;" for="pop_data_'+parameter.name+"_poptmp"+j+'">'+parameter.values[j]+'</label>';
if(parameter.values.length > 2)
html += '<br />';
k++;
}
if(parameter.values.length > 2)
html += '</div>';
html += '</td>';
}
}
else if(parameter.value != undefined){
var step = 1;
if(parameter.step != undefined)
step = parameter.step;
@ -60,43 +113,46 @@ function popup(WIDTH, HEIGHT){
var preview_code = '';
if(this.preview !== false)
preview_code = 'POP.view();';
html += '<td colspan="'+colspan+'"><input style="width:100%;" type="range" id="pop_data_'+parameter.name+'" value="'+parameter.value+'" min="'+parameter.range[0]+'" max="'+parameter.range[1]+'" step="'+step+'" " oninput="document.getElementById(\'pv'+i+'\').innerHTML=Math.round(this.value*100)/100;'+preview_code+'" /></td>';
html += '<td><input type="range" id="pop_data_'+parameter.name+'" value="'+parameter.value+'" min="'+parameter.range[0]+'" max="'+parameter.range[1]+'" step="'+step+'" " oninput="document.getElementById(\'pv'+i+'\').innerHTML=Math.round(this.value*100)/100;'+preview_code+'" /></td>';
html += '<td style="padding-left:10px;width:50px;" id="pv'+i+'">'+parameter.value+'</td>';
}
else
html += '<td colspan="'+colspan+'"><input style="width:100%;" type="text" id="pop_data_'+parameter.name+'" value="'+parameter.value+'" onkeyup="POP.validate(this);" /></td>';
//if(parameter.range != undefined)
//html += '<td style="padding-left:10px;">'+parameter.range[0]+' - '+parameter.range[1]+'</td>';
}
else if(parameter.values != undefined){
html += '<td colspan="2"><select style="font-size:12px;" id="pop_data_'+parameter.name+'">';
for(var j in parameter.values)
html += '<option name="'+parameter.values[j]+'">'+parameter.values[j]+'</option>';
html += '</select></td>';
else{
if(parameter.type == 'textarea')
html += '<td><textarea style="width:100%;height:80px;" id="pop_data_'+parameter.name+'">'+parameter.value+'</textarea></td>';
else
html += '<td colspan="2"><input style="width:100%;" type="text" id="pop_data_'+parameter.name+'" value="'+parameter.value+'" onkeyup="POP.validate(this);" /></td>';
}
}
}
else if(parameter.function != undefined){
//custom function
if(typeof parameter.function == 'string')
var result = window[parameter.function]();
else
var result = parameter.function();
html += '<td colspan="3">'+result+'</td>';
}
else if(parameter.html != undefined){
//html
html += '<td colspan="2">'+parameter.html+'</td>';
}
else{
//locked fields
str = ""+parameter.value;
var id_tmp = parameter.title.toLowerCase().replace(/[^\w]+/g,'').replace(/ +/g,'-');
id_tmp = id_tmp.substring(0, 10);
if(str.length < 40)
html += '<td colspan="2"><input style="width:100%;color:#393939;padding-left:5px;" disabled="disabled" type="text" id="pop_data_'+parameter.name+'" value="'+parameter.value+'" /></td>';
html += '<td colspan="2"><input style="width:97%;color:#393939;padding-left:5px;" disabled="disabled" type="text" id="pop_data_'+id_tmp+'" value="'+parameter.value+'" /></td>';
else
html += '<td style="font-size:11px;" colspan="2"><textarea disabled="disabled">'+parameter.value+'</textarea></td>';
}
html += '</tr>';
}
html += '</table>';
if(this.preview !== false){
if(this.preview !== false && this.preview_in_main == false){
html += '<div style="margin-top:15px;">';
html += '<canvas style="position:relative;float:left;margin-right:5px;border:1px solid #393939;" width="'+width_mini+'" height="'+height_mini+'" id="pop_pre"></canvas>';
html += '<canvas style="position:relative;border:1px solid #393939;background-color:#ffffff;" width="'+width_mini+'" height="'+height_mini+'" id="pop_post"></canvas>';
html += '<canvas style="position:relative;float:left;margin-right:5px;border:1px solid #393939;" width="'+POP.width_mini+'" height="'+POP.height_mini+'" id="pop_pre"></canvas>';
html += '<canvas style="position:relative;border:1px solid #393939;background-color:#ffffff;" width="'+POP.width_mini+'" height="'+POP.height_mini+'" id="pop_post"></canvas>';
html += '</div>';
}
html += '<div style="text-align:center;margin-top:20px;margin-bottom:15px;">';
@ -109,7 +165,7 @@ function popup(WIDTH, HEIGHT){
document.getElementById("popup").innerHTML = html;
document.getElementById("popup").style.display="block";
if(parameters.length > 20)
if(parameters.length > 15)
document.getElementById("popup").style.overflowY="scroll";
else
document.getElementById("popup").style.overflowY='hidden';
@ -123,27 +179,28 @@ function popup(WIDTH, HEIGHT){
}
//load preview?
if(this.preview !== false){
if(this.preview !== false && this.preview_in_main == false){
//original
var pop_pre = document.getElementById("pop_pre").getContext("2d");
pop_pre.rect(0, 0, WIDTH, HEIGHT);
pop_pre.rect(0, 0, POP.width_mini, POP.height_mini);
pop_pre.fillStyle = "#ffffff";
pop_pre.fill();
DRAW.draw_background(pop_pre, 5, true);
pop_pre.drawImage(document.getElementById(LAYERS[LAYER.layer_active].name), 0, 0, width_mini, height_mini);
DRAW.draw_background(pop_pre, POP.width_mini, POP.height_mini, 5);
pop_pre.drawImage(document.getElementById(LAYERS[LAYER.layer_active].name), 0, 0, POP.width_mini, POP.height_mini);
//copy
pop_post = document.getElementById("pop_post").getContext("2d");
pop_post.rect(0, 0, width_mini, height_mini);
pop_post.rect(0, 0, POP.width_mini, POP.height_mini);
pop_post.fillStyle = "#ffffff";
pop_post.fill();
DRAW.draw_background(pop_post, 5, true);
pop_post.drawImage(document.getElementById(LAYERS[LAYER.layer_active].name), 0, 0, width_mini, height_mini);
DRAW.draw_background(pop_post, POP.width_mini, POP.height_mini, 5);
pop_post.drawImage(document.getElementById(LAYERS[LAYER.layer_active].name), 0, 0, POP.width_mini, POP.height_mini);
//prepare temp canvas
layer_active_small.width = width_mini;
layer_active_small.height = height_mini;
layer_active_small_ctx.drawImage(document.getElementById(LAYERS[LAYER.layer_active].name), 0, 0, width_mini, height_mini);
layer_active_small.width = POP.width_mini;
layer_active_small.height = POP.height_mini;
layer_active_small_ctx.drawImage(document.getElementById(LAYERS[LAYER.layer_active].name), 0, 0, POP.width_mini, POP.height_mini);
POP.view();
}
}
//hide popup
@ -154,22 +211,33 @@ function popup(WIDTH, HEIGHT){
this.active = false;
this.preview = false;
this.onload = false;
this.preview_in_main = false;
canvas_front.clearRect(0, 0, WIDTH, HEIGHT);
}
//renders preview. If input=range supported, is called on every param update - must be fast...
this.view = function(){
if(this.preview !== false){
//reset mini view
pop_post.clearRect(0, 0, width_mini, height_mini);
pop_post.drawImage(layer_active_small, 0, 0);
if(this.preview_in_main == false){
//reset mini view
pop_post.clearRect(0, 0, POP.width_mini, POP.height_mini);
pop_post.drawImage(layer_active_small, 0, 0);
}
//prepare
var response = {};
inputs = document.getElementsByTagName('input');
for (i = 0; i<inputs.length; i++) {
for (i = 0; i<inputs.length; i++){
if(inputs[i].id.substr(0,9)=='pop_data_'){
var key = inputs[i].id.substr(9);
if(HELPER.strpos(key, "_poptmp") != false)
key = key.substring(0, HELPER.strpos(key, "_poptmp"));
var value = inputs[i].value;
response[key] = value;
if(inputs[i].type == 'radio'){
if(inputs[i].checked==true)
response[key] = value;
}
else
response[key] = value;
}
}
selects = document.getElementsByTagName('select');
@ -180,8 +248,20 @@ function popup(WIDTH, HEIGHT){
response[key] = value;
}
}
//update mini view
this.preview(response, pop_post, width_mini, height_mini);
textareas = document.getElementsByTagName('textarea');
for (i = 0; i<textareas.length; i++){
if(textareas[i].id.substr(0,9)=='pop_data_'){
var key = textareas[i].id.substr(9);
var value = textareas[i].value;
response[key] = value;
}
}
//call handler
if(this.preview_in_main == false)
this.preview(response, pop_post, POP.width_mini, POP.height_mini);
else
this.preview(response);
}
}
//OK pressed - prepare data and call handlers
@ -190,11 +270,19 @@ function popup(WIDTH, HEIGHT){
document.getElementById("popup").style.display="none";
var response={};
inputs = document.getElementsByTagName('input');
for (i = 0; i<inputs.length; i++) {
for (i = 0; i<inputs.length; i++){
if(inputs[i].id.substr(0,9)=='pop_data_'){
var key = inputs[i].id.substr(9);
if(HELPER.strpos(key, "_poptmp") != false)
key = key.substring(0, HELPER.strpos(key, "_poptmp"));
var value = inputs[i].value;
response[key] = value;
if(inputs[i].type == 'radio'){
if(inputs[i].checked==true)
response[key] = value;
}
else
response[key] = value;
}
}
selects = document.getElementsByTagName('select');
@ -205,6 +293,14 @@ function popup(WIDTH, HEIGHT){
response[key] = value;
}
}
textareas = document.getElementsByTagName('textarea');
for (i = 0; i<textareas.length; i++){
if(textareas[i].id.substr(0,9)=='pop_data_'){
var key = textareas[i].id.substr(9);
var value = textareas[i].value;
response[key] = value;
}
}
parameters = [];
this.preview = false;
this.onload = false;

View File

@ -6,16 +6,18 @@ var canvas_front = document.getElementById("canvas_front").getContext("2d"); //
var canvas_preview = document.getElementById("canvas_preview").getContext("2d"); //mini preview
//settings
var AUTHOR = 'Vilius';
var AUTHOR = 'ViliusL';
var EMAIL = 'www.viliusl@gmail.com';
var VERSION = '1.7';
var VERSION = '1.8';
var WIDTH = 800; //canvas midth
var HEIGHT = 500; //canvas height
var RATIO = WIDTH/HEIGHT; //width & height ratio
var LAYERS = []; //layers data
var ACTION = 'select_tool'; ///default action
var COLOUR = '#000000'; //current color
var COLOUR_LAST = '#ffffff'; //last used color
var ZOOM = 100; //zoom level 10 - infinity
var ALPHA = 255;
var SAVE_TYPES = [
"PNG - Portable Network Graphics", //default
@ -29,16 +31,25 @@ var ACTION_DATA = [
{name: 'select_tool', title: 'Select object tool', icon: ['all.png', 0+7, 2], attributes: {} },
{name: 'select_square', title: 'Select area tool', icon: ['all.png', -50+4, 5], attributes: {} },
{name: 'magic_wand', title: 'Magic Wand Tool', icon: ['all.png', -150+1, -50+2], attributes: {sensitivity: 40} },
{name: 'erase', title: 'Erase', icon: ['all.png', -100+3, 4], attributes: {size: 20, circle: true} },
{name: 'erase', title: 'Erase', icon: ['all.png', -100+3, 4], attributes: {size: 20, circle: true, strict: true,} },
{name: 'fill', title: 'Fill', icon: ['all.png', -150+3, 3], attributes: {sensitivity: 0} },
{name: 'pick_color', title: 'Pick Color', icon: ['all.png', -200+3, 3], attributes: {} },
{name: 'pencil', title: 'Pencil', icon: ['all.png', -250+3, 3], attributes: {} },
{name: 'line', title: 'Draw line', icon: ['all.png', -300+3, 3], attributes: {size: 1, arrow: false} },
{name: 'letters', title: 'Draw letters', icon: ['all.png', -350+3, 4], attributes: {size: 12} },
{name: 'line', title: 'Draw line', icon: ['all.png', -300+3, 3], attributes: {size: 1, multiline: false, arrow: false} },
{name: 'letters', title: 'Draw letters', icon: ['all.png', -350+3, 4], attributes: {} },
{name: 'draw_square', title: 'Draw rectangle', icon: ['all.png', -400+3, 5], attributes: {fill: false, square: false, round: 0} },
{name: 'draw_circle', title: 'Draw circle', icon: ['all.png', -450+3, 5], attributes: {fill: false, circle: false} },
{name: 'brush', title: 'Brush', icon: ['all.png', -500+6, 3], attributes: {size: 5} },
{name: 'brush', title: 'Brush', icon: ['all.png', -500+6, 3], attributes: {type: 'Simple', type_values: ['Simple', 'BezierCurve', 'Broken', 'Chrome', 'Fur', 'Grouped', 'Shaded', 'Sketchy'], size: 5, } },
{name: 'blur_tool', title: 'Blur tool', icon: ['all.png', -250+5, -50+2], attributes: {size: 30, strength: 1} },
{name: 'sharpen_tool', title: 'Sharpen tool', icon: ['all.png', -300+5, -50+2], attributes: {size: 30, strength: 1} },
{name: 'clone_tool', title: 'Clone tool', icon: ['all.png', -350+4, -50+3], attributes: {size: 30} },
{name: 'gradient_tool', title: 'Gradient', icon: ['all.png', -400+3, -50+4], attributes: {radial: false, power: 50} },
];
var CREDITS = [
{title: 'Brush styles', name: 'Harmony', link: 'http://ricardocabello.com/blog/post/689', },
{title: 'Effects library', name: 'glfx.js', link: 'http://evanw.github.io/glfx.js/', },
{title: 'EXIF', name: 'exif.js', link: 'https://github.com/jseidelin/exif-js', },
{title: 'Menu', name: 'Google menu', link: 'http://blog.geotitles.com/2011/09/creating-the-new-top-black-bar-found-in-google-and-all-its-products/', },
{title: 'Image filters', name: 'ImageFilters.js',link: 'https://github.com/arahaya/ImageFilters.js', },
];

File diff suppressed because it is too large Load Diff

View File

@ -1,294 +0,0 @@
/*
html5slider - a JS implementation of <input type=range> for Firefox 16 and up
https://github.com/fryn/html5slider
Copyright (c) 2010-2013 Frank Yan, <http://frankyan.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
(function() {
// test for native support
var test = document.createElement('input');
try {
test.type = 'range';
if (test.type == 'range')
return;
} catch (e) {
return;
}
// test for required property support
test.style.background = 'linear-gradient(red, red)';
if (!test.style.backgroundImage || !('MozAppearance' in test.style))
return;
var scale;
var isMac = navigator.platform == 'MacIntel';
var thumb = {
radius: isMac ? 9 : 6,
width: isMac ? 22 : 12,
height: isMac ? 16 : 20
};
var track = 'linear-gradient(transparent ' + (isMac ?
'6px, #999 6px, #999 7px, #ccc 8px, #bbb 9px, #bbb 10px, transparent 10px' :
'9px, #999 9px, #bbb 10px, #fff 11px, transparent 11px') +
', transparent)';
var styles = {
'min-width': thumb.width + 'px',
'min-height': thumb.height + 'px',
'max-height': thumb.height + 'px',
padding: '0 0 ' + (isMac ? '2px' : '1px'),
border: 0,
'border-radius': 0,
cursor: 'default',
'text-indent': '-999999px' // -moz-user-select: none; breaks mouse capture
};
var options = {
attributes: true,
attributeFilter: ['min', 'max', 'step', 'value']
};
var onInput = document.createEvent('HTMLEvents');
onInput.initEvent('input', true, false);
var onChange = document.createEvent('HTMLEvents');
onChange.initEvent('change', true, false);
if (document.readyState == 'loading')
document.addEventListener('DOMContentLoaded', initialize, true);
else
initialize();
addEventListener('pageshow', recreate, true);
function initialize() {
// create initial sliders
recreate();
// create sliders on-the-fly
new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.addedNodes)
Array.forEach(mutation.addedNodes, function(node) {
if (!(node instanceof Element))
;
else if (node.childElementCount)
Array.forEach(node.querySelectorAll('input[type=range]'), check);
else if (node.mozMatchesSelector('input[type=range]'))
check(node);
});
});
}).observe(document, { childList: true, subtree: true });
}
function recreate() {
Array.forEach(document.querySelectorAll('input[type=range]'), check);
}
function check(input) {
if (input.type != 'range')
transform(input);
}
function transform(slider) {
var isValueSet, areAttrsSet, isUI, isClick, prevValue, rawValue, prevX;
var min, max, step, range, value = slider.value;
// lazily create shared slider affordance
if (!scale) {
scale = document.body.appendChild(document.createElement('hr'));
style(scale, {
'-moz-appearance': isMac ? 'scale-horizontal' : 'scalethumb-horizontal',
display: 'block',
visibility: 'visible',
opacity: 1,
position: 'fixed',
top: '-999999px'
});
document.mozSetImageElement('__sliderthumb__', scale);
}
// reimplement value and type properties
var getValue = function() { return '' + value; };
var setValue = function setValue(val) {
value = '' + val;
isValueSet = true;
draw();
delete slider.value;
slider.value = value;
slider.__defineGetter__('value', getValue);
slider.__defineSetter__('value', setValue);
};
slider.__defineGetter__('value', getValue);
slider.__defineSetter__('value', setValue);
Object.defineProperty(slider, 'type', {
get: function() { return 'range'; }
});
// sync properties with attributes
['min', 'max', 'step'].forEach(function(name) {
if (slider.hasAttribute(name))
areAttrsSet = true;
Object.defineProperty(slider, name, {
get: function() {
return this.hasAttribute(name) ? this.getAttribute(name) : '';
},
set: function(val) {
val === null ?
this.removeAttribute(name) :
this.setAttribute(name, val);
}
});
});
// initialize slider
slider.readOnly = true;
style(slider, styles);
update();
new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName != 'value') {
update();
areAttrsSet = true;
}
// note that value attribute only sets initial value
else if (!isValueSet) {
value = slider.getAttribute('value');
draw();
}
});
}).observe(slider, options);
slider.addEventListener('mousedown', onDragStart, true);
slider.addEventListener('keydown', onKeyDown, true);
slider.addEventListener('focus', onFocus, true);
slider.addEventListener('blur', onBlur, true);
function onDragStart(e) {
isClick = true;
setTimeout(function() { isClick = false; }, 0);
if (e.button || !range)
return;
var width = parseFloat(getComputedStyle(this).width);
var multiplier = (width - thumb.width) / range;
if (!multiplier)
return;
// distance between click and center of thumb
var dev = e.clientX - this.getBoundingClientRect().left - thumb.width / 2 -
(value - min) * multiplier;
// if click was not on thumb, move thumb to click location
if (Math.abs(dev) > thumb.radius) {
isUI = true;
this.value -= -dev / multiplier;
}
rawValue = value;
prevX = e.clientX;
this.addEventListener('mousemove', onDrag, true);
this.addEventListener('mouseup', onDragEnd, true);
}
function onDrag(e) {
var width = parseFloat(getComputedStyle(this).width);
var multiplier = (width - thumb.width) / range;
if (!multiplier)
return;
rawValue += (e.clientX - prevX) / multiplier;
prevX = e.clientX;
isUI = true;
this.value = rawValue;
}
function onDragEnd() {
this.removeEventListener('mousemove', onDrag, true);
this.removeEventListener('mouseup', onDragEnd, true);
slider.dispatchEvent(onInput);
slider.dispatchEvent(onChange);
}
function onKeyDown(e) {
if (e.keyCode > 36 && e.keyCode < 41) { // 37-40: left, up, right, down
onFocus.call(this);
isUI = true;
this.value = value + (e.keyCode == 38 || e.keyCode == 39 ? step : -step);
}
}
function onFocus() {
if (!isClick)
this.style.boxShadow = !isMac ? '0 0 0 2px #fb0' :
'inset 0 0 20px rgba(0,127,255,.1), 0 0 1px rgba(0,127,255,.4)';
}
function onBlur() {
this.style.boxShadow = '';
}
// determines whether value is valid number in attribute form
function isAttrNum(value) {
return !isNaN(value) && +value == parseFloat(value);
}
// validates min, max, and step attributes and redraws
function update() {
min = isAttrNum(slider.min) ? +slider.min : 0;
max = isAttrNum(slider.max) ? +slider.max : 100;
if (max < min)
max = min > 100 ? min : 100;
step = isAttrNum(slider.step) && slider.step > 0 ? +slider.step : 1;
range = max - min;
draw(true);
}
// recalculates value property
function calc() {
if (!isValueSet && !areAttrsSet)
value = slider.getAttribute('value');
if (!isAttrNum(value))
value = (min + max) / 2;;
// snap to step intervals (WebKit sometimes does not - bug?)
value = Math.round((value - min) / step) * step + min;
if (value < min)
value = min;
else if (value > max)
value = min + ~~(range / step) * step;
}
// renders slider using CSS background ;)
function draw(attrsModified) {
calc();
var wasUI = isUI;
isUI = false;
if (wasUI && value != prevValue)
slider.dispatchEvent(onInput);
if (!attrsModified && value == prevValue)
return;
prevValue = value;
var position = range ? (value - min) / range * 100 : 0;
var bg = '-moz-element(#__sliderthumb__) ' + position + '% no-repeat, ';
style(slider, { background: bg + track });
}
}
function style(element, styles) {
for (var prop in styles)
element.style.setProperty(prop, styles[prop], 'important');
}
})();

View File

@ -49,9 +49,19 @@ table{
border-spacing: 0;
width:100%;
}
input{
input[type="text"], input[type="button"], select{
border:1px solid #393939;
}
input[type="range"]{
margin-left:0px;
width:100%;
}
input[type="text"]:disabled{
border: 1px solid #c0c0c0;
}
label{
font-size:11px;
}
/* ==== ID ================================================================== */
@ -80,9 +90,10 @@ input{
#uploadprogress{
position:absolute;
top:5px;
z-index:100;
left:300px;
height:15px;
width:500px;
width:600px;
display:none;
}
#main_colour{
@ -177,6 +188,7 @@ input{
}
#popup h2{
margin-top:0px;
cursor:move;
}
#popup textarea{
color:#000000;
@ -297,3 +309,8 @@ input{
width:400px;
font-weight:bold;
}
.group{
border:1px solid #93bdfe;
margin:5px 0px 5px 0px;
padding:5px;
}