Feat(WebWorker): Add WebWorker Image Filter Demo
This commit is contained in:
parent
2dcf714d2b
commit
84463cf0bd
|
@ -13,9 +13,10 @@ import 'package:angular2/src/web-workers/ui/impl.dart' show bootstrapUICommon;
|
||||||
* You instantiate a WebWorker application by calling bootstrap with the URI of your worker's index script
|
* You instantiate a WebWorker application by calling bootstrap with the URI of your worker's index script
|
||||||
* Note: The WebWorker script must call bootstrapWebworker once it is set up to complete the bootstrapping process
|
* Note: The WebWorker script must call bootstrapWebworker once it is set up to complete the bootstrapping process
|
||||||
*/
|
*/
|
||||||
void bootstrap(String uri) {
|
Future<MessageBus> bootstrap(String uri) {
|
||||||
spawnWorker(Uri.parse(uri)).then((bus) {
|
return spawnWorker(Uri.parse(uri)).then((bus) {
|
||||||
bootstrapUICommon(bus);
|
bootstrapUICommon(bus);
|
||||||
|
return bus;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,10 @@ import {bootstrapUICommon} from "angular2/src/web-workers/ui/impl";
|
||||||
* Note: The WebWorker script must call bootstrapWebworker once it is set up to complete the
|
* Note: The WebWorker script must call bootstrapWebworker once it is set up to complete the
|
||||||
* bootstrapping process
|
* bootstrapping process
|
||||||
*/
|
*/
|
||||||
export function bootstrap(uri: string): void {
|
export function bootstrap(uri: string): MessageBus {
|
||||||
var messageBus = spawnWorker(uri);
|
var messageBus = spawnWorker(uri);
|
||||||
bootstrapUICommon(messageBus);
|
bootstrapUICommon(messageBus);
|
||||||
|
return messageBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function spawnWorker(uri: string): MessageBus {
|
export function spawnWorker(uri: string): MessageBus {
|
||||||
|
|
|
@ -80,9 +80,9 @@ Map<String, dynamic> serializeGenericEvent(dynamic e) {
|
||||||
|
|
||||||
// TODO(jteplitz602): Allow users to specify the properties they need rather than always
|
// TODO(jteplitz602): Allow users to specify the properties they need rather than always
|
||||||
// adding value #3374
|
// adding value #3374
|
||||||
Map<String, dynamic> serializeEventWithValue(dynamic e) {
|
Map<String, dynamic> serializeEventWithTarget(dynamic e) {
|
||||||
var serializedEvent = serializeEvent(e, EVENT_PROPERTIES);
|
var serializedEvent = serializeEvent(e, EVENT_PROPERTIES);
|
||||||
return addValue(e, serializedEvent);
|
return addTarget(e, serializedEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> serializeMouseEvent(dynamic e) {
|
Map<String, dynamic> serializeMouseEvent(dynamic e) {
|
||||||
|
@ -91,13 +91,16 @@ Map<String, dynamic> serializeMouseEvent(dynamic e) {
|
||||||
|
|
||||||
Map<String, dynamic> serializeKeyboardEvent(dynamic e) {
|
Map<String, dynamic> serializeKeyboardEvent(dynamic e) {
|
||||||
var serializedEvent = serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
|
var serializedEvent = serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
|
||||||
return addValue(e, serializedEvent);
|
return addTarget(e, serializedEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jteplitz602): #3374. See above.
|
// TODO(jteplitz602): #3374. See above.
|
||||||
Map<String, dynamic> addValue(dynamic e, Map<String, dynamic> serializedEvent) {
|
Map<String, dynamic> addTarget(dynamic e, Map<String, dynamic> serializedEvent) {
|
||||||
if (NODES_WITH_VALUE.contains(e.target.tagName.toLowerCase())) {
|
if (NODES_WITH_VALUE.contains(e.target.tagName.toLowerCase())) {
|
||||||
serializedEvent['target'] = {'value': e.target.value};
|
serializedEvent['target'] = {'value': e.target.value};
|
||||||
|
if (e.target is InputElement) {
|
||||||
|
serializedEvent['target']['files'] = e.target.files;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return serializedEvent;
|
return serializedEvent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {StringMap, Set} from 'angular2/src/facade/collection';
|
import {StringMap, Set} from 'angular2/src/facade/collection';
|
||||||
|
import {isPresent} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
const MOUSE_EVENT_PROPERTIES = [
|
const MOUSE_EVENT_PROPERTIES = [
|
||||||
"altKey",
|
"altKey",
|
||||||
|
@ -41,10 +42,10 @@ export function serializeGenericEvent(e: Event): StringMap<string, any> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jteplitz602): Allow users to specify the properties they need rather than always
|
// TODO(jteplitz602): Allow users to specify the properties they need rather than always
|
||||||
// adding value #3374
|
// adding value and files #3374
|
||||||
export function serializeEventWithValue(e: Event): StringMap<string, any> {
|
export function serializeEventWithTarget(e: Event): StringMap<string, any> {
|
||||||
var serializedEvent = serializeEvent(e, EVENT_PROPERTIES);
|
var serializedEvent = serializeEvent(e, EVENT_PROPERTIES);
|
||||||
return addValue(e, serializedEvent);
|
return addTarget(e, serializedEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function serializeMouseEvent(e: MouseEvent): StringMap<string, any> {
|
export function serializeMouseEvent(e: MouseEvent): StringMap<string, any> {
|
||||||
|
@ -53,13 +54,17 @@ export function serializeMouseEvent(e: MouseEvent): StringMap<string, any> {
|
||||||
|
|
||||||
export function serializeKeyboardEvent(e: KeyboardEvent): StringMap<string, any> {
|
export function serializeKeyboardEvent(e: KeyboardEvent): StringMap<string, any> {
|
||||||
var serializedEvent = serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
|
var serializedEvent = serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
|
||||||
return addValue(e, serializedEvent);
|
return addTarget(e, serializedEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jteplitz602): #3374. See above.
|
// TODO(jteplitz602): #3374. See above.
|
||||||
function addValue(e: Event, serializedEvent: StringMap<string, any>): StringMap<string, any> {
|
function addTarget(e: Event, serializedEvent: StringMap<string, any>): StringMap<string, any> {
|
||||||
if (NODES_WITH_VALUE.has((<HTMLElement>e.target).tagName.toLowerCase())) {
|
if (NODES_WITH_VALUE.has((<HTMLElement>e.target).tagName.toLowerCase())) {
|
||||||
serializedEvent['target'] = {'value': (<HTMLInputElement>e.target).value};
|
var target = <HTMLInputElement>e.target;
|
||||||
|
serializedEvent['target'] = {'value': target.value};
|
||||||
|
if (isPresent(target.files)) {
|
||||||
|
serializedEvent['target']['files'] = target.files;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return serializedEvent;
|
return serializedEvent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,9 @@ import {
|
||||||
serializeMouseEvent,
|
serializeMouseEvent,
|
||||||
serializeKeyboardEvent,
|
serializeKeyboardEvent,
|
||||||
serializeGenericEvent,
|
serializeGenericEvent,
|
||||||
serializeEventWithValue
|
serializeEventWithTarget
|
||||||
} from 'angular2/src/web-workers/ui/event_serializer';
|
} from 'angular2/src/web-workers/ui/event_serializer';
|
||||||
|
import {wtfInit} from 'angular2/src/profile/wtf_init';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a zone, sets up the DI bindings
|
* Creates a zone, sets up the DI bindings
|
||||||
|
@ -45,6 +46,7 @@ import {
|
||||||
export function bootstrapUICommon(bus: MessageBus) {
|
export function bootstrapUICommon(bus: MessageBus) {
|
||||||
BrowserDomAdapter.makeCurrent();
|
BrowserDomAdapter.makeCurrent();
|
||||||
var zone = createNgZone();
|
var zone = createNgZone();
|
||||||
|
wtfInit();
|
||||||
zone.run(() => {
|
zone.run(() => {
|
||||||
var injector = createInjector(zone);
|
var injector = createInjector(zone);
|
||||||
var webWorkerMain = injector.get(WebWorkerMain);
|
var webWorkerMain = injector.get(WebWorkerMain);
|
||||||
|
@ -259,7 +261,7 @@ class EventDispatcher implements RenderEventDispatcher {
|
||||||
case "input":
|
case "input":
|
||||||
case "change":
|
case "change":
|
||||||
case "blur":
|
case "blur":
|
||||||
serializedEvent = serializeEventWithValue(e);
|
serializedEvent = serializeEventWithTarget(e);
|
||||||
break;
|
break;
|
||||||
case "abort":
|
case "abort":
|
||||||
case "afterprint":
|
case "afterprint":
|
||||||
|
|
|
@ -11,6 +11,9 @@ import {bootstrapWebworkerCommon} from "angular2/src/web-workers/worker/applicat
|
||||||
import {ApplicationRef} from "angular2/src/core/application";
|
import {ApplicationRef} from "angular2/src/core/application";
|
||||||
import {Injectable} from "angular2/di";
|
import {Injectable} from "angular2/di";
|
||||||
|
|
||||||
|
// TODO(jteplitz602) remove this and compile with lib.webworker.d.ts (#3492)
|
||||||
|
var _postMessage: (message: any, transferrables?:[ArrayBuffer]) => void = <any>postMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrapping a Webworker Application
|
* Bootstrapping a Webworker Application
|
||||||
*
|
*
|
||||||
|
@ -41,7 +44,7 @@ export class WorkerMessageBus implements MessageBus {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkerMessageBusSink implements MessageBusSink {
|
export class WorkerMessageBusSink implements MessageBusSink {
|
||||||
public send(message: Object) { postMessage(message, null); }
|
public send(message: Object) { _postMessage(message); }
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkerMessageBusSource implements MessageBusSource {
|
export class WorkerMessageBusSource implements MessageBusSource {
|
||||||
|
|
|
@ -17,9 +17,13 @@ import {
|
||||||
ChangeDetection,
|
ChangeDetection,
|
||||||
DynamicChangeDetection,
|
DynamicChangeDetection,
|
||||||
JitChangeDetection,
|
JitChangeDetection,
|
||||||
|
PreGeneratedChangeDetection,
|
||||||
Pipes,
|
Pipes,
|
||||||
defaultPipes,
|
defaultPipes,
|
||||||
PreGeneratedChangeDetection
|
IterableDiffers,
|
||||||
|
defaultIterableDiffers,
|
||||||
|
KeyValueDiffers,
|
||||||
|
defaultKeyValueDiffers
|
||||||
} from 'angular2/src/change_detection/change_detection';
|
} from 'angular2/src/change_detection/change_detection';
|
||||||
import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver';
|
import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver';
|
||||||
import {ExceptionHandler} from 'angular2/src/core/exception_handler';
|
import {ExceptionHandler} from 'angular2/src/core/exception_handler';
|
||||||
|
@ -119,6 +123,8 @@ function _injectorBindings(appComponentType, bus: WorkerMessageBus,
|
||||||
CompilerCache,
|
CompilerCache,
|
||||||
ViewResolver,
|
ViewResolver,
|
||||||
defaultPipes,
|
defaultPipes,
|
||||||
|
bind(IterableDiffers).toValue(defaultIterableDiffers),
|
||||||
|
bind(KeyValueDiffers).toValue(defaultKeyValueDiffers),
|
||||||
bind(ChangeDetection).toClass(bestChangeDetection),
|
bind(ChangeDetection).toClass(bestChangeDetection),
|
||||||
DirectiveResolver,
|
DirectiveResolver,
|
||||||
Parser,
|
Parser,
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
declare module "B64" {
|
||||||
|
export function fromByteArray(arr: Uint8Array): string;
|
||||||
|
export function toByteArray(str: string): Uint8Array;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
library examples.src.web_workers.images.background_index;
|
||||||
|
|
||||||
|
import "index_common.dart" show ImageDemo;
|
||||||
|
import "dart:isolate";
|
||||||
|
import "package:angular2/src/web-workers/worker/application.dart"
|
||||||
|
show bootstrapWebworker;
|
||||||
|
import "package:angular2/src/reflection/reflection_capabilities.dart";
|
||||||
|
import "package:angular2/src/reflection/reflection.dart";
|
||||||
|
|
||||||
|
main(List<String> args, SendPort replyTo) {
|
||||||
|
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||||
|
bootstrapWebworker(replyTo, ImageDemo).catchError((error) => throw error);
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import {bootstrapWebworker} from "angular2/src/web-workers/worker/application";
|
||||||
|
import {ImageDemo} from "./index_common";
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
bootstrapWebworker(ImageDemo);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
declare class Bitmap {
|
||||||
|
constructor(width: number, height: number);
|
||||||
|
|
||||||
|
subsample(n: number): void;
|
||||||
|
dataURL(): string;
|
||||||
|
|
||||||
|
pixel:[any];
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
Copyright 2011 Andrey Zholos
|
||||||
|
|
||||||
|
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 Bitmap(width, height) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.pixel = new Array(width);
|
||||||
|
for (var x = 0; x < width; x++) {
|
||||||
|
this.pixel[x] = new Array(height);
|
||||||
|
for (var y = 0; y < height; y++) this.pixel[x][y] = [0, 0, 0, 0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap.prototype.subsample =
|
||||||
|
function(n) {
|
||||||
|
var width = ~~(this.width / n);
|
||||||
|
var height = ~~(this.height / n);
|
||||||
|
var pixel = new Array(width);
|
||||||
|
for (var x = 0; x < width; x++) {
|
||||||
|
pixel[x] = new Array(height);
|
||||||
|
for (var y = 0; y < height; y++) {
|
||||||
|
var q = [0, 0, 0, 0];
|
||||||
|
for (var i = 0; i < n; i++)
|
||||||
|
for (var j = 0; j < n; j++) {
|
||||||
|
var r = this.pixel[x * n + i][y * n + j];
|
||||||
|
q[0] += r[3] * r[0];
|
||||||
|
q[1] += r[3] * r[1];
|
||||||
|
q[2] += r[3] * r[2];
|
||||||
|
q[3] += r[3];
|
||||||
|
}
|
||||||
|
if (q[3]) {
|
||||||
|
q[0] /= q[3];
|
||||||
|
q[1] /= q[3];
|
||||||
|
q[2] /= q[3];
|
||||||
|
q[3] /= n * n;
|
||||||
|
}
|
||||||
|
pixel[x][y] = q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.pixel = pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap.prototype.dataURL = function() {
|
||||||
|
function sample(v) { return ~~(Math.max(0, Math.min(1, v)) * 255); }
|
||||||
|
|
||||||
|
function gamma(v) { return sample(Math.pow(v, .45455)); }
|
||||||
|
|
||||||
|
function row(pixel, width, y) {
|
||||||
|
var data = "\0";
|
||||||
|
for (var x = 0; x < width; x++) {
|
||||||
|
var r = pixel[x][y];
|
||||||
|
data += String.fromCharCode(gamma(r[0]), gamma(r[1]), gamma(r[2]), sample(r[3]));
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rows(pixel, width, height) {
|
||||||
|
var data = "";
|
||||||
|
for (var y = 0; y < height; y++) data += row(pixel, width, y);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function adler(data) {
|
||||||
|
var s1 = 1, s2 = 0;
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
s1 = (s1 + data.charCodeAt(i)) % 65521;
|
||||||
|
s2 = (s2 + s1) % 65521;
|
||||||
|
}
|
||||||
|
return s2 << 16 | s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hton(i) { return String.fromCharCode(i >>> 24, i >>> 16 & 255, i >>> 8 & 255, i & 255); }
|
||||||
|
|
||||||
|
function deflate(data) {
|
||||||
|
var len = data.length;
|
||||||
|
return "\170\1\1" + String.fromCharCode(len & 255, len >>> 8, ~len & 255, (~len >>> 8) & 255) +
|
||||||
|
data + hton(adler(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
function crc32(data) {
|
||||||
|
var c = ~0;
|
||||||
|
for (var i = 0; i < data.length; i++)
|
||||||
|
for (var b = data.charCodeAt(i) | 0x100; b != 1; b >>>= 1)
|
||||||
|
c = (c >>> 1) ^ ((c ^ b) & 1 ? 0xedb88320 : 0);
|
||||||
|
return ~c;
|
||||||
|
}
|
||||||
|
|
||||||
|
function chunk(type, data) { return hton(data.length) + type + data + hton(crc32(type + data)); }
|
||||||
|
|
||||||
|
function base64(data) {
|
||||||
|
enc = "";
|
||||||
|
for (var i = 5, n = data.length * 8 + 5; i < n; i += 6)
|
||||||
|
enc += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||||
|
[(data.charCodeAt(~~(i / 8) - 1) << 8 | data.charCodeAt(~~(i / 8))) >> 7 - i % 8 & 63];
|
||||||
|
for (; enc.length % 4; enc += "=")
|
||||||
|
;
|
||||||
|
return enc;
|
||||||
|
}
|
||||||
|
|
||||||
|
var png = "\211PNG\r\n\32\n" +
|
||||||
|
chunk("IHDR", hton(this.width) + hton(this.height) + "\10\6\0\0\0") +
|
||||||
|
chunk("IDAT", deflate(rows(this.pixel, this.width, this.height))) + chunk("IEND", "");
|
||||||
|
|
||||||
|
return "data:image/png;base64," + base64(png);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
export 'dart:html' show FileReader;
|
||||||
|
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
class Uint8ArrayWrapper {
|
||||||
|
static Uint8ClampedList create(ByteBuffer buffer) {
|
||||||
|
return new Uint8ClampedList.view(buffer);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
var _FileReader = FileReader;
|
||||||
|
export {_FileReader as FileReader};
|
||||||
|
|
||||||
|
export class Uint8ArrayWrapper {
|
||||||
|
static create(buffer: ArrayBuffer) { return new Uint8Array(buffer); }
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
.hidden{
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
#images {
|
||||||
|
width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
ul li {
|
||||||
|
list-style-type: none;
|
||||||
|
float: left;
|
||||||
|
margin-left: 20px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
#main ul {
|
||||||
|
width: 700px;
|
||||||
|
}
|
||||||
|
.card-image .image-loader{
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-image img.grey {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fixed-action-btn.bottom {
|
||||||
|
bottom: 45px;
|
||||||
|
right: 24px;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<nav class="blue">
|
||||||
|
<div class="container">
|
||||||
|
<div class="nav-wrapper">
|
||||||
|
<a class="brand-logo">Angular 2 Image Demo</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<section id="main" class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div *ng-for="#image of images" class="col s12 m2">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-image">
|
||||||
|
<img [src]="image.src" [class.grey]="image.filtering"/>
|
||||||
|
<div class="image-loader progress" [class.hidden]="!image.filtering">
|
||||||
|
<div class="indeterminate"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="fixed-action-btn bottom" (click)="applyFilters()">
|
||||||
|
<a class="btn-floating btn-large blue darken-4" (click)="applyFilters()">
|
||||||
|
<i class="large material-icons" (click)="applyFilters()">invert_colors</i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="file-field">
|
||||||
|
<div class="btn blue darken-2">
|
||||||
|
<span>Select Images</span>
|
||||||
|
<input type="file" accept="image/bmp" multiple (change)="uploadFiles($event.target.files)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
|
@ -0,0 +1,10 @@
|
||||||
|
library angular2.examples.web_workers.images.index;
|
||||||
|
|
||||||
|
import "package:angular2/src/web-workers/ui/application.dart" show bootstrap;
|
||||||
|
import "package:angular2/src/reflection/reflection_capabilities.dart";
|
||||||
|
import "package:angular2/src/reflection/reflection.dart";
|
||||||
|
|
||||||
|
main() {
|
||||||
|
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||||
|
bootstrap("background_index.dart");
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="image_demo.css" />
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<image-demo>
|
||||||
|
</image-demo>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
<!-- Compiled and minified CSS -->
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/css/materialize.min.css">
|
||||||
|
|
||||||
|
<!-- Compiled and minified JavaScript -->
|
||||||
|
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/js/materialize.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,2 @@
|
||||||
|
import {bootstrap} from "angular2/src/web-workers/ui/application";
|
||||||
|
bootstrap("loader.js");
|
|
@ -0,0 +1,50 @@
|
||||||
|
import {NgZone, NgFor, Component, View, NgIf, formDirectives} from 'angular2/angular2';
|
||||||
|
import {BitmapService} from './services/bitmap';
|
||||||
|
import {EventListener} from 'angular2/src/facade/browser';
|
||||||
|
import {FileReader, Uint8ArrayWrapper} from './file_api';
|
||||||
|
import {TimerWrapper} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
|
@Component({selector: 'image-demo', viewBindings: [BitmapService]})
|
||||||
|
@View({templateUrl: 'image_demo.html', directives: [NgFor, NgIf, formDirectives]})
|
||||||
|
export class ImageDemo {
|
||||||
|
images = [];
|
||||||
|
fileInput: String;
|
||||||
|
|
||||||
|
constructor(private _bitmapService: BitmapService) {}
|
||||||
|
|
||||||
|
uploadFiles(files) {
|
||||||
|
for (var i = 0; i < files.length; i++) {
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.addEventListener("load", this.handleReaderLoad(reader));
|
||||||
|
reader.readAsArrayBuffer(files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleReaderLoad(reader: FileReader): EventListener {
|
||||||
|
return (e) => {
|
||||||
|
var buffer = reader.result;
|
||||||
|
this.images.push({
|
||||||
|
src: this._bitmapService.arrayBufferToDataUri(Uint8ArrayWrapper.create(reader.result)),
|
||||||
|
buffer: buffer,
|
||||||
|
filtering: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
applyFilters() {
|
||||||
|
for (var i = 0; i < this.images.length; i++) {
|
||||||
|
this.images[i].filtering = true;
|
||||||
|
|
||||||
|
TimerWrapper.setTimeout(this._filter(i), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _filter(i: number): Function {
|
||||||
|
return () => {
|
||||||
|
var imageData = this._bitmapService.convertToImageData(this.images[i].buffer);
|
||||||
|
imageData = this._bitmapService.applySepia(imageData);
|
||||||
|
this.images[i].src = this._bitmapService.toDataUri(imageData);
|
||||||
|
this.images[i].filtering = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
body {
|
||||||
|
background: #eaecfa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
width: 250px;
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
-webkit-transform: translate(-50%, -50%);
|
||||||
|
-ms-transform: translate(-50%, -50%);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-family: helvetica, arial, sans-serif;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 900;
|
||||||
|
color: #ce4233;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
}
|
||||||
|
.loader::before, .loader::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
background: #ce4233;
|
||||||
|
position: absolute;
|
||||||
|
-webkit-animation: load .7s infinite alternate ease-in-out;
|
||||||
|
animation: load .7s infinite alternate ease-in-out;
|
||||||
|
}
|
||||||
|
.loader::before {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.loader::after {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes load {
|
||||||
|
0% {
|
||||||
|
left: 0;
|
||||||
|
height: 30px;
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
height: 8px;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
left: 235px;
|
||||||
|
height: 30px;
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes load {
|
||||||
|
0% {
|
||||||
|
left: 0;
|
||||||
|
height: 30px;
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
height: 8px;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
left: 235px;
|
||||||
|
height: 30px;
|
||||||
|
width: 15px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
$SCRIPTS$ window = {
|
||||||
|
setTimeout: setTimeout,
|
||||||
|
Map: Map,
|
||||||
|
Set: Set,
|
||||||
|
Array: Array,
|
||||||
|
Reflect: Reflect,
|
||||||
|
RegExp: RegExp,
|
||||||
|
Promise: Promise,
|
||||||
|
Date: Date,
|
||||||
|
zone: zone
|
||||||
|
};
|
||||||
|
assert = function() {};
|
||||||
|
importScripts("b64.js");
|
||||||
|
|
||||||
|
System.import("examples/src/web_workers/images/background_index")
|
||||||
|
.then(
|
||||||
|
function(m) {
|
||||||
|
console.log("running main");
|
||||||
|
try {
|
||||||
|
m.main();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(error) { console.error("error loading background", error); });
|
|
@ -0,0 +1,23 @@
|
||||||
|
library angular2.examples.web_workers.images.bitmap_service;
|
||||||
|
|
||||||
|
import 'dart:html';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
// TODO(jteplitz602) Implement this class #3493
|
||||||
|
class BitmapService {
|
||||||
|
ImageData applySepia (ImageData imageData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String arrayBufferToDataUri (Uint8ClampedList data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageData convertToImageData (ByteBuffer buffer) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String toDataUri (ImageData imageData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,188 @@
|
||||||
|
/// <reference path="../bitmap.d.ts" /> /// <reference path="../b64.d.ts" />
|
||||||
|
import {Injectable} from 'angular2/angular2';
|
||||||
|
declare var base64js;
|
||||||
|
|
||||||
|
// Temporary fix for Typescript issue #4220 (https://github.com/Microsoft/TypeScript/issues/4220)
|
||||||
|
// var _ImageData: (width: number, height: number) => void = <any>postMessage;
|
||||||
|
var _ImageData: {
|
||||||
|
prototype: ImageData, new (width: number, height: number): ImageData;
|
||||||
|
}
|
||||||
|
= ImageData;
|
||||||
|
|
||||||
|
// This class is based on the Bitmap examples at:
|
||||||
|
// http://www.i-programmer.info/projects/36-web/6234-reading-a-bmp-file-in-javascript.html
|
||||||
|
// and
|
||||||
|
// http://www.worldwidewhat.net/2012/07/how-to-draw-bitmaps-using-javascript/
|
||||||
|
@Injectable()
|
||||||
|
export class BitmapService {
|
||||||
|
convertToImageData(buffer: ArrayBuffer): ImageData {
|
||||||
|
var bmp = this._getBMP(buffer);
|
||||||
|
return this._BMPToImageData(bmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
applySepia(imageData: ImageData): ImageData {
|
||||||
|
var buffer = imageData.data;
|
||||||
|
for (var i = 0; i < buffer.length; i += 4) {
|
||||||
|
var r = buffer[i];
|
||||||
|
var g = buffer[i + 1];
|
||||||
|
var b = buffer[i + 2];
|
||||||
|
buffer[i] = (r * .393) + (g * .769) + (b * .189);
|
||||||
|
buffer[i + 1] = (r * .349) + (g * .686) + (b * .168);
|
||||||
|
buffer[i + 2] = (r * .272) + (g * .534) + (b * .131);
|
||||||
|
}
|
||||||
|
return imageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
toDataUri(imageData: ImageData): string {
|
||||||
|
var header = this._createBMPHeader(imageData);
|
||||||
|
imageData = this._imageDataToBMP(imageData);
|
||||||
|
return 'data:image/bmp;base64,' + btoa(header) + base64js.fromByteArray(imageData.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// converts a .bmp file ArrayBuffer to a dataURI
|
||||||
|
arrayBufferToDataUri(data: Uint8Array): string {
|
||||||
|
return 'data:image/bmp;base64,' + base64js.fromByteArray(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a UInt8Array in BMP order (starting from the bottom)
|
||||||
|
private _imageDataToBMP(imageData: ImageData): ImageData {
|
||||||
|
var width = imageData.width;
|
||||||
|
var height = imageData.height;
|
||||||
|
|
||||||
|
var data = imageData.data;
|
||||||
|
for (var y = 0; y < height / 2; ++y) {
|
||||||
|
var topIndex = y * width * 4;
|
||||||
|
var bottomIndex = (height - y) * width * 4;
|
||||||
|
for (var i = 0; i < width * 4; i++) {
|
||||||
|
this._swap(data, topIndex, bottomIndex);
|
||||||
|
topIndex++;
|
||||||
|
bottomIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return imageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _swap(data: List<any>, index1: number, index2: number) {
|
||||||
|
var temp = data[index1];
|
||||||
|
data[index1] = data[index2];
|
||||||
|
data[index2] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on example from
|
||||||
|
// http://www.worldwidewhat.net/2012/07/how-to-draw-bitmaps-using-javascript/
|
||||||
|
private _createBMPHeader(imageData: ImageData): string {
|
||||||
|
var numFileBytes = this._getLittleEndianHex(imageData.width * imageData.height);
|
||||||
|
var w = this._getLittleEndianHex(imageData.width);
|
||||||
|
var h = this._getLittleEndianHex(imageData.height);
|
||||||
|
return 'BM' + // Signature
|
||||||
|
numFileBytes + // size of the file (bytes)*
|
||||||
|
'\x00\x00' + // reserved
|
||||||
|
'\x00\x00' + // reserved
|
||||||
|
'\x36\x00\x00\x00' + // offset of where BMP data lives (54 bytes)
|
||||||
|
'\x28\x00\x00\x00' + // number of remaining bytes in header from here (40 bytes)
|
||||||
|
w + // the width of the bitmap in pixels*
|
||||||
|
h + // the height of the bitmap in pixels*
|
||||||
|
'\x01\x00' + // the number of color planes (1)
|
||||||
|
'\x20\x00' + // 32 bits / pixel
|
||||||
|
'\x00\x00\x00\x00' + // No compression (0)
|
||||||
|
'\x00\x00\x00\x00' + // size of the BMP data (bytes)*
|
||||||
|
'\x13\x0B\x00\x00' + // 2835 pixels/meter - horizontal resolution
|
||||||
|
'\x13\x0B\x00\x00' + // 2835 pixels/meter - the vertical resolution
|
||||||
|
'\x00\x00\x00\x00' + // Number of colors in the palette (keep 0 for 32-bit)
|
||||||
|
'\x00\x00\x00\x00'; // 0 important colors (means all colors are important)
|
||||||
|
}
|
||||||
|
|
||||||
|
private _BMPToImageData(bmp: BitmapFile): ImageData {
|
||||||
|
var width = bmp.infoHeader.biWidth;
|
||||||
|
var height = bmp.infoHeader.biHeight;
|
||||||
|
var imageData = new _ImageData(width, height);
|
||||||
|
|
||||||
|
var data = imageData.data;
|
||||||
|
var bmpData = bmp.pixels;
|
||||||
|
var stride = bmp.stride;
|
||||||
|
|
||||||
|
for (var y = 0; y < height; ++y) {
|
||||||
|
for (var x = 0; x < width; ++x) {
|
||||||
|
var index1 = (x + width * (height - y)) * 4;
|
||||||
|
var index2 = x * 3 + stride * y;
|
||||||
|
data[index1] = bmpData[index2 + 2];
|
||||||
|
data[index1 + 1] = bmpData[index2 + 1];
|
||||||
|
data[index1 + 2] = bmpData[index2];
|
||||||
|
data[index1 + 3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return imageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getBMP(buffer: ArrayBuffer): BitmapFile {
|
||||||
|
var datav = new DataView(buffer);
|
||||||
|
var bitmap: BitmapFile = {
|
||||||
|
fileHeader: {
|
||||||
|
bfType: datav.getUint16(0, true),
|
||||||
|
bfSize: datav.getUint32(2, true),
|
||||||
|
bfReserved1: datav.getUint16(6, true),
|
||||||
|
bfReserved2: datav.getUint16(8, true),
|
||||||
|
bfOffBits: datav.getUint32(10, true),
|
||||||
|
},
|
||||||
|
infoHeader: {
|
||||||
|
biSize: datav.getUint32(14, true),
|
||||||
|
biWidth: datav.getUint32(18, true),
|
||||||
|
biHeight: datav.getUint32(22, true),
|
||||||
|
biPlanes: datav.getUint16(26, true),
|
||||||
|
biBitCount: datav.getUint16(28, true),
|
||||||
|
biCompression: datav.getUint32(30, true),
|
||||||
|
biSizeImage: datav.getUint32(34, true),
|
||||||
|
biXPelsPerMeter: datav.getUint32(38, true),
|
||||||
|
biYPelsPerMeter: datav.getUint32(42, true),
|
||||||
|
biClrUsed: datav.getUint32(46, true),
|
||||||
|
biClrImportant: datav.getUint32(50, true)
|
||||||
|
},
|
||||||
|
stride: null,
|
||||||
|
pixels: null
|
||||||
|
};
|
||||||
|
var start = bitmap.fileHeader.bfOffBits;
|
||||||
|
bitmap.stride =
|
||||||
|
Math.floor((bitmap.infoHeader.biBitCount * bitmap.infoHeader.biWidth + 31) / 32) * 4;
|
||||||
|
bitmap.pixels = new Uint8Array(datav.buffer, start);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on example from
|
||||||
|
// http://www.worldwidewhat.net/2012/07/how-to-draw-bitmaps-using-javascript/
|
||||||
|
private _getLittleEndianHex(value: number): string {
|
||||||
|
var result = [];
|
||||||
|
|
||||||
|
for (var bytes = 4; bytes > 0; bytes--) {
|
||||||
|
result.push(String.fromCharCode(value & 255));
|
||||||
|
value >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.join('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BitmapFile {
|
||||||
|
fileHeader: {
|
||||||
|
bfType: number;
|
||||||
|
bfSize: number;
|
||||||
|
bfReserved1: number;
|
||||||
|
bfReserved2: number;
|
||||||
|
bfOffBits: number;
|
||||||
|
};
|
||||||
|
infoHeader: {
|
||||||
|
biSize: number;
|
||||||
|
biWidth: number;
|
||||||
|
biHeight: number;
|
||||||
|
biPlanes: number;
|
||||||
|
biBitCount: number;
|
||||||
|
biCompression: number;
|
||||||
|
biSizeImage: number;
|
||||||
|
biXPelsPerMeter: number;
|
||||||
|
biYPelsPerMeter: number;
|
||||||
|
biClrUsed: number;
|
||||||
|
biClrImportant: number
|
||||||
|
};
|
||||||
|
stride: number;
|
||||||
|
pixels: Uint8Array;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="image_demo.css" />
|
||||||
|
<script type="text/javascript" src="b64.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<image-demo>
|
||||||
|
</image-demo>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
<!-- Compiled and minified CSS -->
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/css/materialize.min.css">
|
||||||
|
|
||||||
|
<!-- Compiled and minified JavaScript -->
|
||||||
|
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/js/materialize.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,6 @@
|
||||||
|
import {bootstrap} from "angular2/bootstrap";
|
||||||
|
import {ImageDemo} from "./index_common";
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
bootstrap(ImageDemo);
|
||||||
|
}
|
|
@ -35,6 +35,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"angular": "1.3.5",
|
"angular": "1.3.5",
|
||||||
|
"base64-js": "^0.0.8",
|
||||||
"bower": "^1.3.12",
|
"bower": "^1.3.12",
|
||||||
"broccoli": "^0.15.3",
|
"broccoli": "^0.15.3",
|
||||||
"broccoli-filter": "^0.1.12",
|
"broccoli-filter": "^0.1.12",
|
||||||
|
|
|
@ -217,9 +217,10 @@ class CustomLanguageServiceHost implements ts.LanguageServiceHost {
|
||||||
* not worth the potential issues with stale cache records.
|
* not worth the potential issues with stale cache records.
|
||||||
*/
|
*/
|
||||||
getScriptSnapshot(tsFilePath: string): ts.IScriptSnapshot {
|
getScriptSnapshot(tsFilePath: string): ts.IScriptSnapshot {
|
||||||
let absoluteTsFilePath = (tsFilePath == this.defaultLibFilePath) ?
|
let absoluteTsFilePath =
|
||||||
tsFilePath :
|
(tsFilePath == this.defaultLibFilePath || path.isAbsolute(tsFilePath)) ?
|
||||||
path.join(this.treeInputPath, tsFilePath);
|
tsFilePath :
|
||||||
|
path.join(this.treeInputPath, tsFilePath);
|
||||||
|
|
||||||
if (!fs.existsSync(absoluteTsFilePath)) {
|
if (!fs.existsSync(absoluteTsFilePath)) {
|
||||||
// TypeScript seems to request lots of bogus paths during import path lookup and resolution,
|
// TypeScript seems to request lots of bogus paths during import path lookup and resolution,
|
||||||
|
|
|
@ -65,7 +65,8 @@ const kServedPaths = [
|
||||||
'examples/src/material/switcher',
|
'examples/src/material/switcher',
|
||||||
'examples/src/message_broker',
|
'examples/src/message_broker',
|
||||||
'examples/src/web_workers/kitchen_sink',
|
'examples/src/web_workers/kitchen_sink',
|
||||||
'examples/src/web_workers/todo'
|
'examples/src/web_workers/todo',
|
||||||
|
'examples/src/web_workers/images'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,6 +130,7 @@ module.exports = function makeBrowserTree(options, destinationPath) {
|
||||||
'node_modules/systemjs/lib/extension-register.js',
|
'node_modules/systemjs/lib/extension-register.js',
|
||||||
'node_modules/systemjs/lib/extension-cjs.js',
|
'node_modules/systemjs/lib/extension-cjs.js',
|
||||||
'node_modules/rx/dist/rx.js',
|
'node_modules/rx/dist/rx.js',
|
||||||
|
'node_modules/base64-js/lib/b64.js',
|
||||||
'node_modules/reflect-metadata/Reflect.js',
|
'node_modules/reflect-metadata/Reflect.js',
|
||||||
'tools/build/snippets/runtime_paths.js',
|
'tools/build/snippets/runtime_paths.js',
|
||||||
path.relative(projectRootDir, TRACEUR_RUNTIME_PATH)
|
path.relative(projectRootDir, TRACEUR_RUNTIME_PATH)
|
||||||
|
|
Loading…
Reference in New Issue