1/* global MAIN, EVENTS, LAYER, POP, HELPER, TOOLS, DRAW, GUI, EDIT, FILE */ 2/* global canvas_active, ImageFilters, WIDTH, HEIGHT, canvas_active, canvas_front */ 3 4var IMAGE = new IMAGE_CLASS(); 5 6/** 7 * manages image actions 8 * 9 * @author toolpic.com 10 */ 11function IMAGE_CLASS() { 12 13 //information 14 this.image_information = function () { 15 var _this = this; 16 var pixels = WIDTH*HEIGHT; 17 pixels = HELPER.number_format(pixels, 0); 18 19 POP.add({title: "Width:", value: WIDTH}); 20 POP.add({title: "Height:", value: HEIGHT}); 21 POP.add({title: "Pixels:", value: pixels}); 22 POP.add({title: "Unique colors:", value: '...'}); 23 24 //show general data 25 for (var i in FILE.file_info.general){ 26 POP.add({title: i + ":", value: FILE.file_info.general[i]}); 27 } 28 29 //show exif data 30 var n = 0; 31 for (var i in FILE.file_info.exif){ 32 if(i == 'undefined') 33 continue; 34 if(n == 0) 35 POP.add({title: "==== EXIF ====", value: ''}); 36 POP.add({title: i + ":", value: FILE.file_info.exif[i]}); 37 n++; 38 } 39 40 POP.show('Information', null, null, function(){ 41 //calc colors 42 setTimeout(function(){ 43 var colors = _this.unique_colors_count(canvas_active(true)); 44 colors = HELPER.number_format(colors, 0); 45 document.getElementById('pop_data_uniquecolo').innerHTML = colors; 46 }, 10); 47 }); 48 }; 49 50 //size 51 this.image_size = function () { 52 POP.add({name: "width", title: "Width:", value: WIDTH, placeholder: WIDTH}); 53 POP.add({name: "height", title: "Height:", value: HEIGHT, placeholder: HEIGHT}); 54 POP.show('Attributes', [IMAGE, 'resize_custom']); 55 }; 56 57 //trim 58 this.image_trim = function () { 59 EDIT.save_state(); 60 this.trim(); 61 }; 62 63 //crop 64 this.image_crop = function () { 65 EDIT.save_state(); 66 if (DRAW.select_data == false) { 67 POP.add({html: 'Select area first'}); 68 POP.show('Error', ''); 69 } 70 else { 71 for (var i in LAYER.layers) { 72 var layer = document.getElementById(LAYER.layers[i].name).getContext("2d"); 73 74 var tmp = layer.getImageData(DRAW.select_data.x, DRAW.select_data.y, DRAW.select_data.w, DRAW.select_data.h); 75 layer.clearRect(0, 0, WIDTH, HEIGHT); 76 layer.putImageData(tmp, 0, 0); 77 } 78 79 //resize 80 EDIT.save_state(); 81 WIDTH = DRAW.select_data.w; 82 HEIGHT = DRAW.select_data.h; 83 LAYER.set_canvas_size(); 84 85 DRAW.select_data = false; 86 canvas_front.clearRect(0, 0, WIDTH, HEIGHT); 87 } 88 }; 89 90 //resize 91 this.image_resize = function () { 92 this.resize_box(); 93 }; 94 95 //rotate left 96 this.image_rotate_left = function () { 97 EDIT.save_state(); 98 this.rotate_resize_doc(270, WIDTH, HEIGHT); 99 this.rotate_layer({angle: 270}, canvas_active(), WIDTH, HEIGHT); 100 }; 101 102 //rotate right 103 this.image_rotate_right = function () { 104 EDIT.save_state(); 105 this.rotate_resize_doc(90, WIDTH, HEIGHT); 106 this.rotate_layer({angle: 90}, canvas_active(), WIDTH, HEIGHT); 107 }; 108 109 //rotate 110 this.image_rotate = function () { 111 POP.add({name: "angle", title: "Enter angle (0-360):", value: 0, range: [0, 360]}); 112 POP.add({name: "mode", title: "Area:", values: ['All', 'Visible']}); 113 POP.show( 114 'Rotate', 115 function (response) {
116 EDIT.save_state(); 117 if(response.mode == 'All') 118 IMAGE.rotate_resize_doc(response.angle, WIDTH, HEIGHT); 119 IMAGE.rotate_layer(response, canvas_active(), WIDTH, HEIGHT); 120 }, 121 function (response, canvas_preview, w, h) { 122 IMAGE.rotate_layer(response, canvas_preview, w, h); 123 } 124 ); 125 }; 126 127 //vertical flip 128 this.image_vflip = function () { 129 EDIT.save_state(); 130 var tempCanvas = document.createElement("canvas"); 131 var tempCtx = tempCanvas.getContext("2d"); 132 tempCanvas.width = WIDTH; 133 tempCanvas.height = HEIGHT; 134 tempCtx.drawImage(canvas_active(true), 0, 0, WIDTH, HEIGHT); 135 //flip 136 canvas_active().clearRect(0, 0, WIDTH, HEIGHT); 137 canvas_active().save(); 138 canvas_active().scale(1, -1); 139 canvas_active().drawImage(tempCanvas, 0, -HEIGHT); 140 canvas_active().restore(); 141 }; 142 143 //horizontal flip 144 this.image_hflip = function () { 145 EDIT.save_state(); 146 var tempCanvas = document.createElement("canvas"); 147 var tempCtx = tempCanvas.getContext("2d"); 148 tempCanvas.width = WIDTH; 149 tempCanvas.height = HEIGHT; 150 tempCtx.drawImage(canvas_active(true), 0, 0, WIDTH, HEIGHT); 151 //flip 152 canvas_active().clearRect(0, 0, WIDTH, HEIGHT); 153 canvas_active().save(); 154 canvas_active().scale(-1, 1); 155 canvas_active().drawImage(tempCanvas, -WIDTH, 0); 156 canvas_active().restore(); 157 }; 158 159 //color corrections 160 this.image_colors = function () { 161 POP.add({name: "param1", title: "Brightness:", value: "0", range: [-100, 100]}); 162 POP.add({name: "param2", title: "Contrast:", value: "0", range: [-100, 100]}); 163 POP.add({}); 164 POP.add({name: "param_red", title: "Red channel:", value: "0", range: [-255, 255]}); 165 POP.add({name: "param_green", title: "Green channel:", value: "0", range: [-255, 255]}); 166 POP.add({name: "param_blue", title: "Blue channel:", value: "0", range: [-255, 255]}); 167 POP.add({}); 168 POP.add({name: "param_h", title: "Hue:", value: "0", range: [-180, 180]}); 169 POP.add({name: "param_s", title: "Saturation:", value: "0", range: [-100, 100]}); 170 POP.add({name: "param_l", title: "Luminance:", value: "0", range: [-100, 100]}); 171 172 POP.show( 173 'Color corrections', 174 function (user_response) {
175 EDIT.save_state(); 176 var param1 = parseInt(user_response.param1); 177 var param2 = parseInt(user_response.param2); 178 var param_red = parseInt(user_response.param_red); 179 var param_green = parseInt(user_response.param_green); 180 var param_blue = parseInt(user_response.param_blue); 181 var param_h = parseInt(user_response.param_h); 182 var param_s = parseInt(user_response.param_s); 183 var param_l = parseInt(user_response.param_l); 184 185 var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT); 186 //Brightness/Contrast 187 var filtered = ImageFilters.BrightnessContrastPhotoshop(imageData, param1, param2); 188 //RGB corrections 189 var filtered = ImageFilters.ColorTransformFilter(filtered, 1, 1, 1, 1, param_red, param_green, param_blue, 1); 190 //hue/saturation/luminance 191 var filtered = ImageFilters.HSLAdjustment(filtered, param_h, param_s, param_l); 192 canvas_active().putImageData(filtered, 0, 0); 193 GUI.zoom(); 194 }, 195 function (user_response, canvas_preview, w, h) { 196 var param1 = parseInt(user_response.param1); 197 var param2 = parseInt(user_response.param2); 198 var param_red = parseInt(user_response.param_red); 199 var param_green = parseInt(user_response.param_green); 200 var param_blue = parseInt(user_response.param_blue); 201 var param_h = parseInt(user_response.param_h); 202 var param_s = parseInt(user_response.param_s); 203 var param_l = parseInt(user_response.param_l); 204 205 var imageData = canvas_preview.getImageData(0, 0, w, h); 206 //Brightness/Contrast 207 var filtered = ImageFilters.BrightnessContrastPhotoshop(imageData, param1, param2); //add effect 208 //RGB corrections 209 var filtered = ImageFilters.ColorTransformFilter(filtered, 1, 1, 1, 1, param_red, param_green, param_blue, 1); 210 //hue/saturation/luminance 211 var filtered = ImageFilters.HSLAdjustment(filtered, param_h, param_s, param_l); 212 canvas_preview.putImageData(filtered, 0, 0); 213 } 214 ); 215 }; 216 217 //auto adjust colors 218 this.image_auto_adjust = function () { 219 EDIT.save_state(); 220 this.auto_adjust(canvas_active(), WIDTH, HEIGHT); 221 }; 222 223 //convert to grayscale 224 this.image_GrayScale = function () { 225 EDIT.save_state(); 226 var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT); 227 var filtered = ImageFilters.GrayScale(imageData); //add effect 228 canvas_active().putImageData(filtered, 0, 0); 229 }; 230 231 //enchance colors 232 this.image_decrease_colors = function () { 233 POP.add({name: "param1", title: "Colors:", value: "10", range: [1, 256]}); 234 POP.add({name: "param3", title: "Greyscale:", values: ["No", "Yes"], }); 235 POP.show( 236 'Decrease colors', 237 function (user_response) {
238 EDIT.save_state(); 239 var param1 = parseInt(user_response.param1); 240 if (user_response.param3 == 'Yes') 241 param3 = true; 242 else 243 param3 = false; 244 245 IMAGE.decrease_colors(canvas_active(true), canvas_active(true), WIDTH, HEIGHT, param1, param3); 246 GUI.zoom(); 247 }, 248 function (user_response, canvas_preview, w, h) { 249 var param1 = parseInt(user_response.param1); 250 if (user_response.param3 == 'Yes') 251 param3 = true; 252 else 253 param3 = false; 254 255 IMAGE.decrease_colors(canvas_active(true), document.getElementById("pop_post"), w, h, param1, param3); 256 } 257 ); 258 }; 259 260 //negative 261 this.image_negative = function () { 262 EDIT.save_state(); 263 if (DRAW.select_data == false) 264 var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT); 265 else 266 var imageData = canvas_active().getImageData(DRAW.select_data.x, DRAW.select_data.y, DRAW.select_data.w, DRAW.select_data.h); 267 var pixels = imageData.data; 268 for (var i = 0; i < pixels.length; i += 4) { 269 pixels[i] = 255 - pixels[i]; // red 270 pixels[i + 1] = 255 - pixels[i + 1]; // green 271 pixels[i + 2] = 255 - pixels[i + 2]; // blue 272 } 273 //save 274 if (DRAW.select_data == false) 275 canvas_active().putImageData(imageData, 0, 0); 276 else 277 canvas_active().putImageData(imageData, DRAW.select_data.x, DRAW.select_data.y); 278 }; 279 280 //grid 281 this.image_grid = function () { 282 POP.add({name: "visible", title: "Visible:", value: "Yes", values: ["Yes", "No"]}); 283 POP.add({name: "gap_x", title: "Horizontal gap:", value: GUI.grid_size[0]}); 284 POP.add({name: "gap_y", title: "Vertical gap:", value: GUI.grid_size[1]}); 285 POP.show( 286 'Grid', 287 function (response) { 288 if (response.visible == "Yes") { 289 GUI.grid = true; 290 gap_x = response.gap_x; 291 gap_y = response.gap_y; 292 GUI.draw_grid(gap_x, gap_y); 293 } 294 else { 295 GUI.grid = false; 296 GUI.draw_grid(); 297 } 298 } 299 ); 300 }; 301 302 //histogram 303 this.image_histogram = function () { 304 this.histogram(); 305 }; 306 307 this.resize_custom = function (user_response) { 308 EDIT.save_state(); 309 EVENTS.autosize = false; 310 if (user_response.width != WIDTH || user_response.height != HEIGHT) { 311 WIDTH = user_response.width; 312 HEIGHT = user_response.height; 313 LAYER.set_canvas_size(); 314 } 315 }; 316 317 //prepare rotation - increase doc dimensions if needed 318 this.rotate_resize_doc = function (angle, w, h) { 319 var o = angle * Math.PI / 180; 320 var new_x = w * Math.abs(Math.cos(o)) + h * Math.abs(Math.sin(o)); 321 var new_y = w * Math.abs(Math.sin(o)) + h * Math.abs(Math.cos(o)); 322 new_x = Math.ceil(Math.round(new_x * 1000) / 1000); 323 new_y = Math.ceil(Math.round(new_y * 1000) / 1000); 324 325 if (WIDTH != new_x || HEIGHT != new_y) { 326 EDIT.save_state(); 327 var dx = 0; 328 var dy = 0; 329 if (new_x > WIDTH) { 330 dx = Math.ceil(new_x - WIDTH) / 2; 331 WIDTH = new_x; 332 } 333 if (new_y > HEIGHT) { 334 dy = Math.ceil(new_y - HEIGHT) / 2; 335 HEIGHT = new_y; 336 } 337 LAYER.set_canvas_size(); 338 339 var tmp = canvas_active().getImageData(0, 0, WIDTH, HEIGHT); 340 canvas_active().clearRect(0, 0, WIDTH, HEIGHT); 341 canvas_active().putImageData(tmp, dx, dy); 342 } 343 }; 344 345 //rotate layer 346 this.rotate_layer = function (user_response, canvas, w, h) { 347 var TO_RADIANS = Math.PI / 180; 348 angle = user_response.angle; 349 mode = user_response.mode; 350 351 var area_x = 0; 352 var area_y = 0; 353 var area_w = w; 354 var area_h = h; 355 356 var dx = 0; 357 var dy = 0; 358 359 if(mode == 'Visible'){ 360 //rotate only visible part 361 362 var trim_info = this.trim_info(canvas.canvas); 363 area_x = trim_info.left; 364 area_y = trim_info.top; 365 area_w = w - trim_info.left - trim_info.right; 366 area_h = h - trim_info.top - trim_info.bottom; 367 368 //calc how much dimensions will increase 369 var o = angle * Math.PI / 180; 370 var new_x = area_w * Math.abs(Math.cos(o)) + area_h * Math.abs(Math.sin(o)); 371 var new_y = area_w * Math.abs(Math.sin(o)) + area_h * Math.abs(Math.cos(o)); 372 new_x = Math.ceil(Math.round(new_x * 1000) / 1000); 373 new_y = Math.ceil(Math.round(new_y * 1000) / 1000); 374 if(new_x > area_w || new_y > area_h){ 375 if (new_x > area_w) { 376 dx = Math.ceil(new_x - area_w) / 2; 377 if(area_x > dx) 378 dx = 0; 379 } 380 if (new_y > area_h) { 381 dy = Math.ceil(new_y - area_h) / 2; 382 if(area_y > dy) 383 dy = 0; 384 } 385 if (w == WIDTH && h == HEIGHT){ 386 var tmp = canvas.getImageData(0, 0, w, h); 387 canvas.clearRect(0, 0, w, h); 388 canvas.putImageData(tmp, dx, dy); 389 } 390 } 391
392 //recalc 393 var trim_info = this.trim_info(canvas.canvas); 394 area_x = trim_info.left; 395 area_y = trim_info.top; 396 area_w = w - trim_info.left - trim_info.right; 397 area_h = h - trim_info.top - trim_info.bottom; 398 } 399 400 var tempCanvas = document.createElement("canvas"); 401 var tempCtx = tempCanvas.getContext("2d"); 402 tempCanvas.width = area_w; 403 tempCanvas.height = area_h; 404 var imageData = canvas.getImageData(area_x, area_y, area_w, area_h); 405 tempCtx.putImageData(imageData, 0, 0); 406 407 //rotate 408 canvas.clearRect(area_x, area_y, area_w, area_h); 409 canvas.save(); 410 canvas.translate(area_x + Math.round(area_w / 2), area_y + Math.round(area_h / 2)); 411 canvas.rotate(angle * TO_RADIANS); 412 canvas.drawImage(tempCanvas, -Math.round(area_w / 2), -Math.round(area_h / 2)); 413 canvas.restore(); 414 if (w == WIDTH && h == HEIGHT){ 415 //if main canvas 416 GUI.zoom(); 417 } 418 }; 419 420 this.resize_box = function () { 421 POP.add({name: "width", title: "Width (pixels):", value: '', placeholder: WIDTH}); 422 POP.add({name: "height", title: "Height (pixels):", value: '', placeholder: HEIGHT}); 423 POP.add({name: "width_percent", title: "Width (%):", value: '', placeholder: 100}); 424 POP.add({name: "height_percent", title: "Height (%):", value: '', placeholder: 100}); 425 POP.add({name: "mode", title: "Mode:", values: ["Resample - Hermite", "Basic", "HQX"]}); 426 POP.add({name: "preblur", title: "Pre-Blur:", values: ["Yes", "No"], value: "No"}); 427 POP.add({name: "sharpen", title: "Sharpen:", values: ["Yes", "No"], value: "No"}); 428 POP.show('Resize', [IMAGE, "resize_layer"]); 429 }; 430 431 this.resize_layer = function (user_response) { 432 EDIT.save_state(); 433 var width = parseInt(user_response.width); 434 var height = parseInt(user_response.height); 435 var width_100 = parseInt(user_response.width_percent); 436 var height_100 = parseInt(user_response.height_percent); 437 var preblur = user_response.preblur; 438 var sharpen = user_response.sharpen; 439 if (isNaN(width) && isNaN(height) && isNaN(width_100) && isNaN(height_100)) 440 return false; 441 if (width == WIDTH && height == HEIGHT) 442 return false; 443 444 //if dimension with percent provided 445 if (isNaN(width) && isNaN(height)) { 446 if (isNaN(width_100) == false) { 447 width = Math.round(WIDTH * width_100 / 100); 448 } 449 if (isNaN(height_100) == false) { 450 height = Math.round(HEIGHT * height_100 / 100); 451 } 452 } 453 454 //if only 1 dimension was provided 455 if (isNaN(width) || isNaN(height)) { 456 var ratio = WIDTH/HEIGHT; 457 if (isNaN(width)) 458 width = Math.round(height * ratio); 459 if (isNaN(height)) 460 height = Math.round(width / ratio); 461 } 462 463 //anti-artifacting? 464 if (preblur == 'Yes') { 465 var ratio_w = WIDTH / width; 466 var ratio_h = HEIGHT / height; 467 var ratio_avg = Math.max(ratio_w, ratio_h); 468 var power = ratio_avg * 0.3; 469 if (power > 0.6) { 470 var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT); 471 var filtered = ImageFilters.GaussianBlur(imageData, power); //add effect 472 canvas_active().putImageData(filtered, 0, 0); 473 } 474 } 475 476 //validate 477 if (user_response.mode == "Resample - Hermite" && (width > WIDTH || height > HEIGHT)){ 478 //scalling up - Hermite not supported 479 user_response.mode = "Resize"; 480 } 481 if (user_response.mode == "HQX" && (width < WIDTH && height < HEIGHT)){ 482 //scalling down - HQX not supported 483 user_response.mode = "Resample - Hermite"; 484 } 485 486 var resize_type; 487 if (user_response.mode == "Resample - Hermite") { 488 //Hermite resample - max quality 489 resize_type = 'Hermite'; 490 491 var HERMITE = new Hermite_class(); 492 HERMITE.resample_single(canvas_active(true), width, height); 493 494 if (GUI.last_menu != 'layer_resize') { 495 WIDTH = width; 496 HEIGHT = height; 497 if (WIDTH < 1) 498 WIDTH = 1; 499 if (HEIGHT < 1) 500 HEIGHT = 1; 501 LAYER.set_canvas_size(); 502 } 503 GUI.zoom(); 504 } 505 else if(user_response.mode == "HQX") { 506 //HQX - 2, 3, 4 scale only, but amazing quality if there are only few colors 507 resize_type = 'HQX'; 508 509 //find correct dimensions 510 var multiply = Math.max(width/WIDTH, height/HEIGHT); 511 multiply = Math.round(multiply); 512 if(multiply < 2) 513 multiply = 2; 514 if(multiply > 4) 515 multiply = 4; 516 517 var image_data_resized = hqx(canvas_active(true), multiply); 518 519 canvas_active().clearRect(0, 0, WIDTH, HEIGHT); 520 WIDTH = WIDTH * multiply; 521 HEIGHT = HEIGHT * multiply; 522 LAYER.set_canvas_size(); 523 canvas_active().putImageData(image_data_resized, 0, 0 ); 524 GUI.zoom(); 525 } 526 else { 527 //simple resize - max speed 528 resize_type = 'Default'; 529 tmp_data = document.createElement("canvas"); 530 tmp_data.width = WIDTH; 531 tmp_data.height = HEIGHT; 532 tmp_data.getContext("2d").drawImage(canvas_active(true), 0, 0); 533 534 canvas_active().clearRect(0, 0, WIDTH, HEIGHT); 535 WIDTH = width; 536 HEIGHT = height; 537 LAYER.set_canvas_size(); 538 canvas_active().drawImage(tmp_data, 0, 0, width, height); 539 GUI.zoom(); 540 } 541
542 //sharpen after? 543 if (sharpen == 'Yes') { 544 var imageData = canvas_active().getImageData(0, 0, WIDTH, HEIGHT); 545 var filtered = ImageFilters.Sharpen(imageData, 1); //add effect 546 canvas_active().putImageData(filtered, 0, 0); 547 } 548 }; 549 550 /** 551 * get canvas painted are coords 552 * 553 * @param {HtmlElement} canvas 554 * @param {boolean} trim_white 555 */ 556 this.trim_info = function (canvas, trim_white) { 557 var top = 0; 558 var left = 0; 559 var bottom = 0; 560 var right = 0; 561 var img = canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height); 562 var imgData = img.data; 563 var empty = false; 564 if(trim_white == undefined) 565 trim_white = true; 566 //check top 567 main1: 568 for (var y = 0; y < img.height; y++) { 569 for (var x = 0; x < img.width; x++) { 570 var k = ((y * (img.width * 4)) + (x * 4)); 571 if (imgData[k + 3] == 0) 572 continue; //transparent 573 if (trim_white == true && imgData[k] == 255 && imgData[k + 1] == 255 && imgData[k + 2] == 255) 574 continue; //white 575 break main1; 576 } 577 top++; 578 } 579 //check left 580 main2: 581 for (var x = 0; x < img.width; x++) { 582 for (var y = 0; y < img.height; y++) { 583 var k = ((y * (img.width * 4)) + (x * 4)); 584 if (imgData[k + 3] == 0) 585 continue; //transparent 586 if (trim_white == true && imgData[k] == 255 && imgData[k + 1] == 255 && imgData[k + 2] == 255) 587 continue; //white 588 break main2; 589 } 590 left++; 591 } 592 //check bottom 593 main3: 594 for (var y = img.height - 1; y >= 0; y--) { 595 for (var x = img.width - 1; x >= 0; x--) { 596 var k = ((y * (img.width * 4)) + (x * 4)); 597 if (imgData[k + 3] == 0) 598 continue; //transparent 599 if (trim_white == true && imgData[k] == 255 && imgData[k + 1] == 255 && imgData[k + 2] == 255) 600 continue; //white 601 break main3; 602 } 603 bottom++; 604 } 605 //check right 606 main4: 607 for (var x = img.width - 1; x >= 0; x--) { 608 for (var y = img.height - 1; y >= 0; y--) { 609 var k = ((y * (img.width * 4)) + (x * 4)); 610 if (imgData[k + 3] == 0) 611 continue; //transparent 612 if (trim_white == true && imgData[k] == 255 && imgData[k + 1] == 255 && imgData[k + 2] == 255) 613 continue; //white 614 break main4; 615 } 616 right++; 617 } 618 619 if(top == canvas.height && left == canvas.width){ 620 //canvas is empty 621 empty = true; 622 } 623 624 return { 625 top: top, 626 left: left, 627 bottom: bottom, 628 right: right, 629 empty: empty, 630 }; 631 }; 632 633 this.trim = function (layer, no_resize, removeWhiteColor) { 634 var all_top = HEIGHT; 635 var all_left = WIDTH; 636 var all_bottom = HEIGHT; 637 var all_right = WIDTH; 638 639 if(no_resize == undefined) 640 no_resize = false; 641 if(removeWhiteColor == undefined) 642 removeWhiteColor = false; 643 644 for (var i in LAYER.layers) { 645 if (layer != undefined && LAYER.layers[i].name != layer) 646 continue; 647 648 var top = 0; 649 var left = 0; 650 var bottom = 0; 651 var right = 0; 652 var img = document.getElementById(LAYER.layers[i].name).getContext("2d").getImageData(0, 0, WIDTH, HEIGHT); 653 var imgData = img.data; 654 //check top 655 main1: 656 for (var y = 0; y < img.height; y++) { 657 for (var x = 0; x < img.width; x++) { 658 var k = ((y * (img.width * 4)) + (x * 4)); 659 if (imgData[k + 3] == 0) 660 continue; //transparent 661 if (removeWhiteColor === true && imgData[k] == 255 && imgData[k + 1] == 255 && imgData[k + 2] == 255) 662 continue; //white 663 break main1; 664 } 665 top++; 666 } 667 //check left 668 main2: 669 for (var x = 0; x < img.width; x++) { 670 for (var y = 0; y < img.height; y++) { 671 var k = ((y * (img.width * 4)) + (x * 4)); 672 if (imgData[k + 3] == 0) 673 continue; //transparent 674 if (removeWhiteColor === true && imgData[k] == 255 && imgData[k + 1] == 255 && imgData[k + 2] == 255) 675 continue; //white 676 break main2; 677 } 678 left++; 679 } 680 //check bottom 681 main3: 682 for (var y = img.height - 1; y >= 0; y--) { 683 for (var x = img.width - 1; x >= 0; x--) { 684 var k = ((y * (img.width * 4)) + (x * 4)); 685 if (imgData[k + 3] == 0) 686 continue; //transparent 687 if (removeWhiteColor === true && imgData[k] == 255 && imgData[k + 1] == 255 && imgData[k + 2] == 255) 688 continue; //white 689 break main3; 690 } 691 bottom++; 692 } 693 //check right 694 main4: 695 for (var x = img.width - 1; x >= 0; x--) {
696 for (var y = img.height - 1; y >= 0; y--) { 697 var k = ((y * (img.width * 4)) + (x * 4)); 698 if (imgData[k + 3] == 0) 699 continue; //transparent 700 if (removeWhiteColor === true && imgData[k] == 255 && imgData[k + 1] == 255 && imgData[k + 2] == 255) 701 continue; //white 702 break main4; 703 } 704 right++; 705 } 706 all_top = Math.min(all_top, top); 707 all_left = Math.min(all_left, left); 708 all_bottom = Math.min(all_bottom, bottom); 709 all_right = Math.min(all_right, right); 710 } 711 //move to top-left corner 712 for (var i in LAYER.layers) { 713 if (layer != undefined && LAYER.layers[i].name != layer) 714 continue; 715 716 tmp_data = document.getElementById(LAYER.layers[i].name).getContext("2d").getImageData(0, 0, WIDTH, HEIGHT); 717 document.getElementById(LAYER.layers[i].name).getContext("2d").clearRect(0, 0, WIDTH, HEIGHT); 718 document.getElementById(LAYER.layers[i].name).getContext("2d").putImageData(tmp_data, -all_left, -all_top); 719 var canvas_name = LAYER.layers[i].name; 720 } 721 722 if(removeWhiteColor == false && (all_left + all_right + all_top + all_bottom == 0 || (all_left + all_top == 0 && no_resize == true )) ){ 723 //also trim white color 724 this.trim(layer, no_resize, true); 725 return; 726 } 727 728 //resize 729 if (no_resize == false){ 730 if (layer != undefined) { 731 var W = Math.round(WIDTH - all_left - all_right); 732 var H = Math.round(HEIGHT - all_top - all_bottom); 733 734 var imageData = document.getElementById(layer).getContext("2d").getImageData(0, 0, W, H); 735 document.getElementById(layer).width = W; 736 document.getElementById(layer).height = H; 737 document.getElementById(layer).getContext("2d").clearRect(0, 0, W, H); 738 document.getElementById(layer).getContext("2d").putImageData(imageData, 0, 0); 739 740 return { 741 top: all_top, 742 left: all_left, 743 bottom: all_bottom, 744 right: all_right 745 }; 746 } 747 else { 748 WIDTH = WIDTH - all_left - all_right; 749 HEIGHT = HEIGHT - all_top - all_bottom; 750 if (WIDTH < 1) 751 WIDTH = 1; 752 if (HEIGHT < 1) 753 HEIGHT = 1; 754 LAYER.set_canvas_size(); 755 LAYER.update_info_block(); 756 } 757 } 758 }; 759 760 this.decrease_colors = function (canvas_source, canvas_destination, W, H, colors, greyscale) { 761 var context = canvas_destination.getContext("2d"); 762 var img = context.getImageData(0, 0, W, H); 763 var imgData = img.data; 764 var palette = []; 765 766 //collect top colors 767 var block_size = 10; 768 var ctx = canvas_front; //use temp canvas 769 ctx.clearRect(0, 0, W, H); 770 ctx.drawImage(canvas_source, 0, 0, Math.ceil(canvas_source.width / block_size), Math.ceil(canvas_source.height / block_size)); //simple resize 771 var img_p = ctx.getImageData(0, 0, Math.ceil(canvas_source.width / block_size), Math.ceil(canvas_source.height / block_size)); 772 var imgData_p = img_p.data; 773 ctx.clearRect(0, 0, W, H); 774 775 for (var i = 0; i < imgData_p.length; i += 4) { 776 if (imgData_p[i + 3] == 0) 777 continue; //transparent 778 var grey = Math.round(0.2126 * imgData_p[i] + 0.7152 * imgData_p[i + 1] + 0.0722 * imgData_p[i + 2]); 779 palette.push([imgData_p[i], imgData_p[i + 1], imgData_p[i + 2], grey]); 780 } 781 782 //calculate weights 783 var grey_palette = []; 784 for (var i = 0; i < 256; i++) 785 grey_palette[i] = 0; 786 for (var i = 0; i < palette.length; i++) 787 grey_palette[palette[i][3]]++; 788 789 //remove similar colors 790 for (var max = 10 * 3; max < 100 * 3; max = max + 10 * 3) { 791 if (palette.length <= colors) 792 break; 793 for (var i = 0; i < palette.length; i++) { 794 if (palette.length <= colors) 795 break; 796 var valid = true; 797 for (var j = 0; j < palette.length; j++) { 798 if (palette.length <= colors) 799 break; 800 if (i == j) 801 continue; 802 if (Math.abs(palette[i][0] - palette[j][0]) + Math.abs(palette[i][1] - palette[j][1]) + Math.abs(palette[i][2] - palette[j][2]) < max) { 803 if (grey_palette[palette[i][3]] > grey_palette[palette[j][3]]) { 804 //remove color 805 palette.splice(j, 1); 806 j--; 807 } 808 else { 809 valid = false; 810 break; 811 } 812 } 813 } 814 //remove color 815 if (valid == false) { 816 palette.splice(i, 1); 817 i--; 818 } 819 } 820 } 821 palette = palette.slice(0, colors); 822 823 //change 824 var p_n = palette.length; 825 for (var j = 0; j < H; j++) { 826 for (var i = 0; i < W; i++) { 827 var k = ((j * (W * 4)) + (i * 4)); 828 if (imgData[k + 3] == 0) 829 continue; //transparent 830 831 //find closest color 832 var index1 = 0; 833 var min = 999999; 834 var diff1; 835 for (var m = 0; m < p_n; m++) { 836 var diff = Math.abs(palette[m][0] - imgData[k]) + Math.abs(palette[m][1] - imgData[k + 1]) + Math.abs(palette[m][2] - imgData[k + 2]); 837 if (diff < min) { 838 min = diff; 839 index1 = m; 840 diff1 = diff; 841 } 842 } 843 844 imgData[k] = palette[index1][0];
845 imgData[k + 1] = palette[index1][1]; 846 imgData[k + 2] = palette[index1][2]; 847 848 if (greyscale == true) { 849 var mid = Math.round(0.2126 * imgData[k] + 0.7152 * imgData[k + 1] + 0.0722 * imgData[k + 2]); 850 imgData[k] = mid; 851 imgData[k + 1] = mid; 852 imgData[k + 2] = mid; 853 } 854 } 855 } 856 canvas_destination.getContext("2d").putImageData(img, 0, 0); 857 }; 858 859 //fixing white and black color balance 860 this.auto_adjust = function (context, W, H) { 861 //settings 862 var white = 240; //white color min 863 var black = 30; //black color max 864 var target_white = 1; //how much % white colors should take 865 var target_black = 0.5; //how much % black colors should take 866 var modify = 1.1; //color modify strength 867 var cycles_count = 10; //how much iteration to change colors 868 869 document.body.style.cursor = "wait"; 870 var img = context.getImageData(0, 0, W, H); 871 var imgData = img.data; 872 var n = 0; //pixels count without transparent 873 874 //make sure we have white 875 var n_valid = 0; 876 for (var i = 0; i < imgData.length; i += 4) { 877 if (imgData[i + 3] == 0) 878 continue; //transparent 879 if ((imgData[i] + imgData[i + 1] + imgData[i + 2]) / 3 > white) 880 n_valid++; 881 n++; 882 } 883 target = target_white; 884 var n_fix_white = 0; 885 var done = false; 886 for (var j = 0; j < cycles_count; j++) { 887 if (n_valid * 100 / n >= target) 888 done = true; 889 if (done == true) 890 break; 891 n_fix_white++; 892 893 //adjust 894 for (var i = 0; i < imgData.length; i += 4) { 895 if (imgData[i + 3] == 0) 896 continue; //transparent 897 for (var c = 0; c < 3; c++) { 898 var x = i + c; 899 if (imgData[x] < 10) 900 continue; 901 //increase white 902 imgData[x] *= modify; 903 imgData[x] = Math.round(imgData[x]); 904 if (imgData[x] > 255) 905 imgData[x] = 255; 906 } 907 } 908 909 //recheck 910 n_valid = 0; 911 for (var i = 0; i < imgData.length; i += 4) { 912 if (imgData[i + 3] == 0) 913 continue; //transparent 914 if ((imgData[i] + imgData[i + 1] + imgData[i + 2]) / 3 > white) 915 n_valid++; 916 } 917 } 918 919 //make sure we have black 920 n_valid = 0; 921 for (var i = 0; i < imgData.length; i += 4) { 922 if (imgData[i + 3] == 0) 923 continue; //transparent 924 if ((imgData[i] + imgData[i + 1] + imgData[i + 2]) / 3 < black) 925 n_valid++; 926 } 927 target = target_black; 928 var n_fix_black = 0; 929 var done = false; 930 for (var j = 0; j < cycles_count; j++) { 931 if (n_valid * 100 / n >= target) 932 done = true; 933 if (done == true) 934 break; 935 n_fix_black++; 936 937 //adjust 938 for (var i = 0; i < imgData.length; i += 4) { 939 if (imgData[i + 3] == 0) 940 continue; //transparent 941 for (var c = 0; c < 3; c++) { 942 var x = i + c; 943 if (imgData[x] > 240) 944 continue; 945 //increase black 946 imgData[x] -= (255 - imgData[x]) * modify - (255 - imgData[x]); 947 imgData[x] = Math.round(imgData[x]); 948 } 949 } 950 951 //recheck 952 n_valid = 0; 953 for (var i = 0; i < imgData.length; i += 4) { 954 if (imgData[i + 3] == 0) 955 continue; //transparent 956 if ((imgData[i] + imgData[i + 1] + imgData[i + 2]) / 3 < black) 957 n_valid++; 958 } 959 } 960 961 //save 962 context.putImageData(img, 0, 0); 963 document.body.style.cursor = "auto"; 964 //log('Iterations: brighten='+n_fix_white+", darken="+n_fix_black); 965 }; 966 967 this.histogram = function () { 968 POP.add({name: "param1", title: "Channel:", values: ["Gray", "Red", "Green", "Blue"], onchange: "IMAGE.histogram_onload()"}); 969 POP.add({title: 'Histogram:', function: function () { 970 var html = '<canvas style="position:relative;" id="c_h" width="256" height="100"></canvas>'; 971 return html; 972 }}); 973 POP.add({title: "Total pixels:", value: ""}); 974 POP.add({title: "Average:", value: ""}); 975 POP.show( 976 'Histogram', 977 undefined, 978 undefined, 979 this.histogram_onload 980 ); 981 }; 982 983 this.histogram_onload = function () { 984 var img = canvas_active().getImageData(0, 0, WIDTH, HEIGHT); 985 var imgData = img.data; 986 var channel_grey = document.getElementById("pop_data_param1_poptmp0"); 987 var channel_r = document.getElementById("pop_data_param1_poptmp1"); 988 var channel_g = document.getElementById("pop_data_param1_poptmp2"); 989 var channel_b = document.getElementById("pop_data_param1_poptmp3"); 990 991 if (channel_grey.checked == true) 992 channel = 0; 993 else if (channel_r.checked == true) 994 channel = 1; 995 else if (channel_g.checked == true) 996 channel = 2; 997 else if (channel_b.checked == true) 998 channel = 3; 999 1000 var hist_data = [ [], [], [], [] ]; //grey, red, green, blue 1001 var total = imgData.length / 4; 1002 var sum = 0; 1003 var grey; 1004 1005 for (var i = 0; i < imgData.length; i += 4) { 1006 //collect grey 1007 grey = Math.round((imgData[i] + imgData[i + 1] + imgData[i + 2]) / 3); 1008 sum = sum + imgData[i] + imgData[i + 1] + imgData[i + 2]; 1009 if(hist_data[0][grey] == undefined) 1010 hist_data[0][grey] = 1; 1011 else 1012 hist_data[0][grey]++; 1013 1014 //collect colors 1015 for(var c = 0; c < 3; c++) { 1016 if(c+1 != channel) 1017 continue; 1018 if(hist_data[c+1][imgData[i+c]] == undefined) 1019 hist_data[c+1][imgData[i+c]] = 1; 1020 else 1021 hist_data[c+1][imgData[i+c]]++; 1022 } 1023 } 1024 1025 var c = document.getElementById("c_h").getContext("2d"); 1026 c.rect(0, 0, 256, 100); 1027 c.fillStyle = "#ffffff"; 1028 c.fill(); 1029 var opacity = 1; 1030 1031 //draw histogram 1032 for(var h in hist_data) { 1033 for (var i = 0; i <= 255; i++) { 1034 if(h != channel) 1035 continue; 1036 if (hist_data[h][i] == 0) 1037 continue; 1038 c.beginPath(); 1039 1040 if(h == 0)
1041 c.strokeStyle = "rgba(64, 64, 64, "+opacity*2+")"; 1042 else if(h == 1) 1043 c.strokeStyle = "rgba(255, 0, 0, "+opacity+")"; 1044 else if(h == 2) 1045 c.strokeStyle = "rgba(0, 255, 0, "+opacity+")"; 1046 else if(h == 3) 1047 c.strokeStyle = "rgba(0, 0, 255, "+opacity+")"; 1048 1049 c.lineWidth = 1; 1050 c.moveTo(i + 0.5, 100 + 0.5); 1051 c.lineTo(i + 0.5, 100 - Math.round(hist_data[h][i] * 255 * 100 / total / 6) + 0.5); 1052 c.stroke(); 1053 } 1054 } 1055 1056 document.getElementById("pop_data_totalpixel").innerHTML = HELPER.number_format(total, 0); 1057 if (total > 0) 1058 average = Math.round(sum * 10 / total / 3) / 10; 1059 else 1060 average = '-'; 1061 document.getElementById("pop_data_average").innerHTML = average; 1062 }; 1063 1064 this.unique_colors_count = function (canvas) { 1065 var img = canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height); 1066 var imgData = img.data; 1067 var colors = []; 1068 var n = 0; 1069 for (var i = 0; i < imgData.length; i += 4) { 1070 if (imgData[i + 3] == 0) 1071 continue; //transparent 1072 var key = imgData[i] + "." + imgData[i + 1] + "." + imgData[i + 2]; 1073 if (colors[key] == undefined) { 1074 colors[key] = 1; 1075 n++; 1076 } 1077 } 1078 return n; 1079 }; 1080 this.zoom_in = function() { 1081 GUI.zoom(+1, true); 1082 }; 1083 this.zoom_out = function() { 1084 GUI.zoom(-1, true); 1085 }; 1086 this.zoom_original = function() { 1087 GUI.zoom(100, true); 1088 }; 1089 this.zoom_auto = function() { 1090 GUI.zoom_auto(); 1091 }; 1092}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.