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
|
||||
* Note: The WebWorker script must call bootstrapWebworker once it is set up to complete the bootstrapping process
|
||||
*/
|
||||
void bootstrap(String uri) {
|
||||
spawnWorker(Uri.parse(uri)).then((bus) {
|
||||
Future<MessageBus> bootstrap(String uri) {
|
||||
return spawnWorker(Uri.parse(uri)).then((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
|
||||
* bootstrapping process
|
||||
*/
|
||||
export function bootstrap(uri: string): void {
|
||||
export function bootstrap(uri: string): MessageBus {
|
||||
var messageBus = spawnWorker(uri);
|
||||
bootstrapUICommon(messageBus);
|
||||
return 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
|
||||
// adding value #3374
|
||||
Map<String, dynamic> serializeEventWithValue(dynamic e) {
|
||||
Map<String, dynamic> serializeEventWithTarget(dynamic e) {
|
||||
var serializedEvent = serializeEvent(e, EVENT_PROPERTIES);
|
||||
return addValue(e, serializedEvent);
|
||||
return addTarget(e, serializedEvent);
|
||||
}
|
||||
|
||||
Map<String, dynamic> serializeMouseEvent(dynamic e) {
|
||||
|
@ -91,13 +91,16 @@ Map<String, dynamic> serializeMouseEvent(dynamic e) {
|
|||
|
||||
Map<String, dynamic> serializeKeyboardEvent(dynamic e) {
|
||||
var serializedEvent = serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
|
||||
return addValue(e, serializedEvent);
|
||||
return addTarget(e, serializedEvent);
|
||||
}
|
||||
|
||||
// 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())) {
|
||||
serializedEvent['target'] = {'value': e.target.value};
|
||||
if (e.target is InputElement) {
|
||||
serializedEvent['target']['files'] = e.target.files;
|
||||
}
|
||||
}
|
||||
return serializedEvent;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {StringMap, Set} from 'angular2/src/facade/collection';
|
||||
import {isPresent} from 'angular2/src/facade/lang';
|
||||
|
||||
const MOUSE_EVENT_PROPERTIES = [
|
||||
"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
|
||||
// adding value #3374
|
||||
export function serializeEventWithValue(e: Event): StringMap<string, any> {
|
||||
// adding value and files #3374
|
||||
export function serializeEventWithTarget(e: Event): StringMap<string, any> {
|
||||
var serializedEvent = serializeEvent(e, EVENT_PROPERTIES);
|
||||
return addValue(e, serializedEvent);
|
||||
return addTarget(e, serializedEvent);
|
||||
}
|
||||
|
||||
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> {
|
||||
var serializedEvent = serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
|
||||
return addValue(e, serializedEvent);
|
||||
return addTarget(e, serializedEvent);
|
||||
}
|
||||
|
||||
// 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())) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -35,8 +35,9 @@ import {
|
|||
serializeMouseEvent,
|
||||
serializeKeyboardEvent,
|
||||
serializeGenericEvent,
|
||||
serializeEventWithValue
|
||||
serializeEventWithTarget
|
||||
} from 'angular2/src/web-workers/ui/event_serializer';
|
||||
import {wtfInit} from 'angular2/src/profile/wtf_init';
|
||||
|
||||
/**
|
||||
* Creates a zone, sets up the DI bindings
|
||||
|
@ -45,6 +46,7 @@ import {
|
|||
export function bootstrapUICommon(bus: MessageBus) {
|
||||
BrowserDomAdapter.makeCurrent();
|
||||
var zone = createNgZone();
|
||||
wtfInit();
|
||||
zone.run(() => {
|
||||
var injector = createInjector(zone);
|
||||
var webWorkerMain = injector.get(WebWorkerMain);
|
||||
|
@ -259,7 +261,7 @@ class EventDispatcher implements RenderEventDispatcher {
|
|||
case "input":
|
||||
case "change":
|
||||
case "blur":
|
||||
serializedEvent = serializeEventWithValue(e);
|
||||
serializedEvent = serializeEventWithTarget(e);
|
||||
break;
|
||||
case "abort":
|
||||
case "afterprint":
|
||||
|
|
|
@ -11,6 +11,9 @@ import {bootstrapWebworkerCommon} from "angular2/src/web-workers/worker/applicat
|
|||
import {ApplicationRef} from "angular2/src/core/application";
|
||||
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
|
||||
*
|
||||
|
@ -41,7 +44,7 @@ export class WorkerMessageBus implements MessageBus {
|
|||
}
|
||||
|
||||
export class WorkerMessageBusSink implements MessageBusSink {
|
||||
public send(message: Object) { postMessage(message, null); }
|
||||
public send(message: Object) { _postMessage(message); }
|
||||
}
|
||||
|
||||
export class WorkerMessageBusSource implements MessageBusSource {
|
||||
|
|
|
@ -17,9 +17,13 @@ import {
|
|||
ChangeDetection,
|
||||
DynamicChangeDetection,
|
||||
JitChangeDetection,
|
||||
PreGeneratedChangeDetection,
|
||||
Pipes,
|
||||
defaultPipes,
|
||||
PreGeneratedChangeDetection
|
||||
IterableDiffers,
|
||||
defaultIterableDiffers,
|
||||
KeyValueDiffers,
|
||||
defaultKeyValueDiffers
|
||||
} from 'angular2/src/change_detection/change_detection';
|
||||
import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver';
|
||||
import {ExceptionHandler} from 'angular2/src/core/exception_handler';
|
||||
|
@ -119,6 +123,8 @@ function _injectorBindings(appComponentType, bus: WorkerMessageBus,
|
|||
CompilerCache,
|
||||
ViewResolver,
|
||||
defaultPipes,
|
||||
bind(IterableDiffers).toValue(defaultIterableDiffers),
|
||||
bind(KeyValueDiffers).toValue(defaultKeyValueDiffers),
|
||||
bind(ChangeDetection).toClass(bestChangeDetection),
|
||||
DirectiveResolver,
|
||||
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": {
|
||||
"angular": "1.3.5",
|
||||
"base64-js": "^0.0.8",
|
||||
"bower": "^1.3.12",
|
||||
"broccoli": "^0.15.3",
|
||||
"broccoli-filter": "^0.1.12",
|
||||
|
|
|
@ -217,9 +217,10 @@ class CustomLanguageServiceHost implements ts.LanguageServiceHost {
|
|||
* not worth the potential issues with stale cache records.
|
||||
*/
|
||||
getScriptSnapshot(tsFilePath: string): ts.IScriptSnapshot {
|
||||
let absoluteTsFilePath = (tsFilePath == this.defaultLibFilePath) ?
|
||||
tsFilePath :
|
||||
path.join(this.treeInputPath, tsFilePath);
|
||||
let absoluteTsFilePath =
|
||||
(tsFilePath == this.defaultLibFilePath || path.isAbsolute(tsFilePath)) ?
|
||||
tsFilePath :
|
||||
path.join(this.treeInputPath, tsFilePath);
|
||||
|
||||
if (!fs.existsSync(absoluteTsFilePath)) {
|
||||
// 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/message_broker',
|
||||
'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-cjs.js',
|
||||
'node_modules/rx/dist/rx.js',
|
||||
'node_modules/base64-js/lib/b64.js',
|
||||
'node_modules/reflect-metadata/Reflect.js',
|
||||
'tools/build/snippets/runtime_paths.js',
|
||||
path.relative(projectRootDir, TRACEUR_RUNTIME_PATH)
|
||||
|
|
Loading…
Reference in New Issue