Skip to content

Commit

Permalink
Merge f0275ab into 6613c4c
Browse files Browse the repository at this point in the history
  • Loading branch information
ibgreen committed May 31, 2020
2 parents 6613c4c + f0275ab commit f1c8745
Show file tree
Hide file tree
Showing 30 changed files with 674 additions and 14 deletions.
53 changes: 53 additions & 0 deletions dev-docs/RFCs/vNext/encoding-rfc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Encoding Enhancements for loaders.gl

Status: Work-In-Progress

## Summary

This RFC proposes enhancements to the loaders.gl encode API.

## Requirements and Use Cases

- **Video Encoding** Video encoding is obviously a very complex topic and loaders.gl very intentionally does not aspire to be even a remotely complete solution for this. That said, some basic ability to load and generate videos does make sense.

## Encoder APIs

## encode

Simple atomic encode should reverse the effects of load.

```js
const {load, encode, write} from '@loaders.gl/core`;
const parsedBatchIterator = load(filename, ShapefileLoader);
const encodedBatchIterator = encode(parsedBatchIterator, KMLEncoder);
write(encodedBatch)
```

## encodeInBatches

Since loaders.gl has a growing number of streaming loaders that accept an async iterator with input and yields and async iterator with output batches, it is tempting to enable a streaming encoder that can be fed with the output of a parser for another format in the same category - enabling trivial streaming converter to be written.

```js
const {parseInBatches, encodeInBatches, writeBatches} from '@loaders.gl/core`;

const parsedBatchIterator = loadInBatches(SHAPEFILE_URL, ShapefileLoader);
const encodedBatchIterator = encodeInBatches(parsedBatchIterator, KMLEncoder);
writeBatches(encodedBatchIterator);
```

Format of encoded batches

- binary formats - array buffer chunks
- text formats - string chunks (typically, but not necessarily broken after newlines).

## Not a transport format

Note that the category formats do not aim to preserve all details during conversion, i.e. `encode(parse(URL))` can be lossy.

## Builders / Encoders

Builders are an alternative to loaders. they build a data object from components.

- `GLBBuilder`
- `GLTFBuilder`
- `GIFBuilder`
8 changes: 8 additions & 0 deletions docs/table-of-contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
{"entry": "modules/obj/docs/api-reference/obj-loader"},
{"entry": "modules/pcd/docs/api-reference/pcd-loader"},
{"entry": "modules/ply/docs/api-reference/ply-loader"},
{"entry": "modules/video/docs/api-reference/video-loader"},
{"entry": "modules/wkt/docs/api-reference/wkt-loader"},
{"entry": "modules/wkt/docs/api-reference/wkt-writer"},
{"entry": "modules/zip/docs/api-reference/zip-loader"},
Expand Down Expand Up @@ -214,6 +215,13 @@
{"entry": "modules/tiles/docs/api-reference/tile-3d"}
]
},
{
"title": "@loaders.gl/video",
"entries": [
{"entry": "modules/video/docs"},
{"entry": "modules/video/docs/api-reference/gif-builder"}
]
},
{
"title": "@loaders.gl/wkt",
"entries": [
Expand Down
4 changes: 4 additions & 0 deletions docs/whats-new.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ The `ImageLoader` now loads images as `Imagebitmap` by default on browsers that

Addresses a number of compatibility issues with different tilesets that have been reported by users. See the git log or issues for details.

**@loaders.gl/video**

An experimental new module with video loading and GIF generation support.

## v2.1

Release Date: Mar 16, 2020
Expand Down
34 changes: 34 additions & 0 deletions examples/gallery/gifshot.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!-- Forked from github AnthumChris/fetch-progress-indicators under MIT license -->
<!doctype html>
<body>
<main>
<div id="status">&nbsp;</div>
<h1 id="progress">&nbsp;</h1>
<div><button onclick="window.location.reload()">Reload</button></div>
<img id="img" />
</main>
</body>
<script src="https://unpkg.com/@loaders.gl/core@2.1.0/dist/dist.js"></script>
<script src='https://unpkg.com/gifshot/dist/gifshot.js'></script>
S<script>
const elStatus = document.getElementById('status');
const elProgress = document.getElementById('progress');
const elImage = document.getElementById('img');

async function main() {
elStatus.innerHTML = 'Generating GIF...';
gifshot.createGIF({}, function(obj) {
if(obj.error) {
elStatus.innerHTML = '...GIF generation failed';
return;
}
const image = obj.image,
animatedImage = document.createElement('img');
animatedImage.src = image;
document.body.appendChild(animatedImage);
elStatus.innerHTML = '...GIF generation completed';
});
}

main();
</script>
7 changes: 7 additions & 0 deletions examples/gallery/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"license": "MIT",
"description": "Gallery of simple HTML page examples for loaders.gl",
"scripts": {
"start-progress": "open progress.html"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ <h1 id="progress">&nbsp;</h1>
<img id="img" />
</main>
</body>
<script src="https://unpkg.com/@loaders.gl/core@2.0.0-alpha.2/dist/dist.js"></script>
<script src="https://unpkg.com/@loaders.gl/core@2.1.0/dist/dist.js"></script>
<script>
// Surprisingly, it ooks like the dist script injects on global scope, in addition to `loaders.gl`

Expand Down
7 changes: 0 additions & 7 deletions examples/gallery/progress/package.json

This file was deleted.

1 change: 1 addition & 0 deletions modules/core/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export {makeStreamIterator} from './iterator-utils/stream-iteration';
export {isBrowser, isWorker, self, window, global, document} from '@loaders.gl/loader-utils';
export {assert} from '@loaders.gl/loader-utils';
export {setPathPrefix, getPathPrefix, resolvePath} from '@loaders.gl/loader-utils';
export {RequestScheduler as RequestScheduler} from '@loaders.gl/loader-utils';

// EXPERIMENTAL
export {default as _WorkerThread} from './worker-utils/worker-thread';
Expand Down
2 changes: 1 addition & 1 deletion modules/core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export {makeChunkIterator, concatenateChunksAsync} from './iterator-utils/chunk-
export {isBrowser, isWorker, self, window, global, document} from '@loaders.gl/loader-utils';
export {assert} from '@loaders.gl/loader-utils';
export {setPathPrefix, getPathPrefix, resolvePath} from '@loaders.gl/loader-utils';
export {default as RequestScheduler} from '@loaders.gl/loader-utils';
export {RequestScheduler} from '@loaders.gl/loader-utils';

// EXPERIMENTAL
export {default as _WorkerThread} from './worker-utils/worker-thread';
Expand Down
7 changes: 7 additions & 0 deletions modules/video/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @loaders.gl/video

[loaders.gl](https://loaders.gl/docs) is a collection of framework independent 3D and geospatial parsers and encoders.

This module contains loader and writers for video that follow loaders.gl conventions and work under both node and browser.

For documentation please visit the [website](https://loaders.gl).
18 changes: 18 additions & 0 deletions modules/video/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Overview

The `@loaders.gl/video` module contains loader and writers for images that follow loaders.gl conventions.

> Video support is still experimental, and currently does not work in Node.js
## Installation

```bash
npm install @loaders.gl/video
npm install @loaders.gl/core
```

## API

| Loader | Description |
| -------------------------------------------------------------- | ----------- |
| [`VideoLoader`](modules/video/docs/api-reference/video-loader) | |
139 changes: 139 additions & 0 deletions modules/video/docs/api-reference/gif-builder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# GIFBuilder

The `GIFBuilder` class creates a base64 encoded GIF image from either:

- a series of images
- a series of image URLs
- a video URL
- or by capturing the webcam.

> The `GIFBuilder` only works in the browser, and many features are experimental.
## Usage

Build a GIF from images

```js
import {load} from '@loaders.gl/core';
import {ImageLoader} from '@loaders.gl/images';
import {GIFBuilder} from '@loaders.gl/video';

const gifBuilder = new GIFBuilder({source: 'images', width: 400, height: 400});
gifBuilder.add(await load('http://i.imgur.com/2OO33vX.jpg', ImageLoader));
gifBuilder.add(await load('http://i.imgur.com/qOwVaSN.png', ImageLoader));
gifBuilder.add(await load('http://i.imgur.com/Vo5mFZJ.gif', ImageLoader));
gifBuilder.build();
```

Build a GIF from image URLs (Experimental)

```js
import {GIFBuilder} from '@loaders.gl/video';

const gifBuilder = new GIFBuilder({source: 'images', width: 400, height: 400});
gifBuilder.add('http://i.imgur.com/2OO33vX.jpg');
gifBuilder.add('http://i.imgur.com/qOwVaSN.png');
gifBuilder.add('http://i.imgur.com/Vo5mFZJ.gif');
gifBuilder.build();
```

Build a GIF from image URLs, with frame-specific Text (Experimental)

```js
import {GIFBuilder} from '@loaders.gl/video';

const gifBuilder = new GIFBuilder({source: 'images', width: 400, height: 400});
gifBuilder.add({src: 'http://i.imgur.com/2OO33vX.jpg', text: 'First image text'});
gifBuilder.add({src: 'http://i.imgur.com/qOwVaSN.png', text: 'Second image text'});
gifBuilder.add({src: 'http://i.imgur.com/Vo5mFZJ.gif', text: 'This image text'});
gifBuilder.build();
```

Build a GIF from the webcam (Experimental)

```js
import {GIFBuilder} from '@loaders.gl/video';
const gifBuilder = new GIFBuilder({source: webcam, width: 400, height: 400});
gifBuilder.build();
```

## Methods

### constructor(options: object)

Creates a new `GIFBuilder` instance.

`options` See the Options section below.

### add(file: string | object | Image)

The following types can be added

The following types can be added

- **images** - (NOT YET SUPPORTED) - `Image` objects can be added.

- **string URLs for images** If this option is used, then a GIF will be created using these images e.g. ,.'http://i.imgur.com/2OO33vX.jpg', 'http://i.imgur.com/qOwVaSN.png', 'http://i.imgur.com/Vo5mFZJ.gif'

- **a video** a GIF will be created using the first supplied video that is supported by the current browser's video codecs. E.g. 'example.mp4', 'example.ogv'.

> Note that a mix of types is not supported. All added elements must be of the same type (images, image URLs, video URLs).
### build(): string

The build method will actually build the GIF. It returns a base 64 encoded GIF.

Note: After calling `build()` this builder instance is not intended to be used further. Create new `GLTBuilder` instances to build additional GIFs.

## Options

| Option | Type | Default | Description |
| ---------------- | -------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `source` | `string` | `'images'` | Either `'images'`, `'video'` or `'webcam'` |
| `width` | `number` | `200` | Desired width of the generated GIF image |
| `height` | `number` | `200` | Desired height of the generated GIF image |
| `crossOrigin` | `string` | CORS attribute for requesting image or video URLs. 'Anonymous' | 'Anonymous', 'use-credentials', or '' (to not set). |
| QUALITY SETTINGS | | |
| `sampleInterval` | | `10` | pixels to skip when creating the palette. Default is 10. Less is better, but slower. |
| `numWorkers` | | `2` | | how many web workers to use to process the animated GIF frames. Default is 2. |
| `interval` | | `0.1` | The amount of time (in seconds) to wait between each frame capture |
| `offset` | | `null` | | The amount of time (in seconds) to start capturing the GIF (only for HTML5 videos) |
| `numFrames` | | `10` | | The number of frames to use to create the animated GIF. Each frame is captured every 100 milliseconds of a video and every ms for existing images |
| `frameDuration` | | `1` | | The amount of time (10 = 1s) to stay on each frame |

Notes:

- By adjusting the sample interval, you can either produce extremely high-quality images slowly, or produce good images in reasonable times. With a sampleInterval of 1, the entire image is used in the learning phase, while with an interval of 10, a pseudo-random subset of 1/10 of the pixels are used in the learning phase. A sampling factor of 10 gives a substantial speed-up, with a small quality penalty.

### Experimental Options

These options are forwarded directly to the underlying [`gifshot`](https://github.com/yahoo/gifshot) module. They are not officially supported by loaders.gl, but can still be useful. In case things are unclear it is recommended to search the documentation and issues in that module.

| Option | Type | Default | Description |
| ----------------------------------- | -------------------------------------------------------------------- | --------------------------- | ---------------------------------------------------------------------- |
| when the current image is completed |
| CSS FILTER OPTIONS | | |
| `filter` | `'', // CSS filter that will be applied to the image (eg. blur(5px)) |
| WATERMARK OPTIONS | | |
| `waterMark` | `null` | | If an image is given here, it will be stamped on top of the GIF frames |
| `waterMarkHeight` | `null` | ,// Height of the waterMark |
| `waterMarkWidth` | `null` | | Height of the waterMark |
| `waterMarkXCoordinate` | `1` | | The X (horizontal) Coordinate of the watermark image |
| `waterMarkYCoordinate` | `1` | | The Y (vertical) Coordinate of the watermark image |

| TEXT OPTIONS
| `text` | `'', // The text that covers the animated GIF | |`showFrameText`|`true | If frame-specific text is supplied with the image array, you can force the |frame-specific text to not be displayed by making this option 'false'.
| `fontWeight` | `'normal' | The font weight of the text that covers the animated GIF | |`fontSize`|`'16px' | The font size of the text that covers the animated GIF |
| `minFontSize` | `'10px' | The minimum font size of the text that covers the animated GIF (Note` | `This |option is only applied if the text being applied is cut off) |`resizeFont`|`false | Whether or not the animated GIF text will be resized to fit within the GIF |container
| `fontFamily` | `'sans-serif' | The font family of the text that covers the animated GIF | |`fontColor`|`'#ffffff' | The font color of the text that covers the animated GIF |
| `textAlign` | `'center' | The horizontal text alignment of the text that covers the animated GIF | |`textBaseline`|`'bottom' | The vertical text alignment of the text that covers the animated GIF |
| `textXCoordinate` | `null | The X (horizontal) Coordinate of the text that covers the animated GIF (only |use this if the default textAlign and textBaseline options don't work for you) |`textYCoordinate`|`null | The Y (vertical) Coordinate of the text that covers the animated GIF (only |use this if the default textAlign and textBaseline options don't work for you)

## Remarks

- Make sure these image resources are CORS enabled to prevent any cross-origin JavaScript errors
- You may also pass a NodeList of existing image elements on the page

## Attribution

`GIFBuilder` is based on Yahoo's awesome [`gifshot`](https://github.com/yahoo/gifshot) module, and is MIT licensed.
27 changes: 27 additions & 0 deletions modules/video/docs/api-reference/video-loader.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# VideoLoader

An image loader that works under both Node.js (requires `@loaders.gl/polyfills`) and the browser.

| Loader | Characteristic |
| -------------- | ------------------------------------------------------- |
| File Extension | `.mp4` |
| File Type | Binary |
| File Format | Image |
| Data Format | `Video` (browsers) (Not currently supported on node.js) |
| Supported APIs | `load`, `parse` |

## Usage

```js
import '@loaders.gl/polyfills'; // only needed if using under Node
import {VideoLoader} from '@loaders.gl/video';
import {load} from '@loaders.gl/core';

const image = await load(url, VideoLoader, options);
```

## Options

| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |

0 comments on commit f1c8745

Please sign in to comment.