Beginning of documentation!
This commit is contained in:
parent
01e26414bb
commit
484f61389e
52
Algorithm.md
Normal file
52
Algorithm.md
Normal file
@ -0,0 +1,52 @@
|
||||
# BlurHash Algorithm
|
||||
|
||||
## Summary
|
||||
|
||||
BlurHash applies a simple DCT transform to the image data, keeping only the first few components, and then encodes
|
||||
these components using a base 83 encoding, with a JSON, HTML and shell-safe character set. The DC component,
|
||||
which represents the average colour of the image, is stored exactly as an sRGB value, for easy use without impleneting
|
||||
the full algorithm. The AC components are encoded lossily.
|
||||
|
||||
## Reference implementation
|
||||
|
||||
[Simplified Swift decoder implemenation.](../Swift/BlurHashDecode.swift)
|
||||
|
||||
[Simplified Swift encoder implemenation.](../Swift/BlurHashEncode.swift)
|
||||
|
||||
## Structure
|
||||
|
||||
Here follows an example of a BlurHash string, with the different parts labelled:
|
||||
|
||||
`Example: LNMF%n00%#MwS|WCWEM{R*bbWBbH`
|
||||
`Legend: 12333344....................`
|
||||
|
||||
1. Number of components, 1 digit.
|
||||
|
||||
For a BlurHash with `nx` components along the X axis and `ny` components along the Y axis, this is equal to `(nx - 1) + (ny - 1) * 9`.
|
||||
|
||||
2. Maximum AC component value, 1 digit.
|
||||
|
||||
All AC components are scaled by this value. It represents a floating-point value of `(max + 1) / 83`.
|
||||
|
||||
3. Average colour. 4 digits.
|
||||
|
||||
The average colour of the image in sRGB space, encoded as a 24-bit RGB value, with R in the most signficant position. This value can
|
||||
be used directly if you only want the average colour rather than the full DCT-encoded image.
|
||||
|
||||
4. AC components, 2 digits each, `nx * ny - 1` components in total.
|
||||
|
||||
The AC components of the DCT transform, ordred by increasing X first, then Y. These values range from 0 to 6859. See below for a
|
||||
more detailed description.
|
||||
|
||||
## Base 83
|
||||
|
||||
A custom base 83 encoding is used. Values are encoded individually, using 1 to 4 digits, and concatenated together. Multiple-digit
|
||||
values are encoded in big-endian order, with the most signficant digit first.
|
||||
|
||||
The character used set is `0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~`.
|
||||
|
||||
## DCT
|
||||
|
||||
To be written.
|
||||
|
||||
AC components are encoded as values between 0 and 18, and then combined together as `R * 19^2 + G * 19 + B`.
|
||||
1
C/README.md
Normal file
1
C/README.md
Normal file
@ -0,0 +1 @@
|
||||
|
||||
74
CodeOfConduct.md
Normal file
74
CodeOfConduct.md
Normal file
@ -0,0 +1,74 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
education, socio-economic status, nationality, personal appearance, race,
|
||||
religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at dag.agren@wolt.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
3
Kotlin/Readme.md
Normal file
3
Kotlin/Readme.md
Normal file
@ -0,0 +1,3 @@
|
||||
# BlurHash in Kotlin, for Android
|
||||
|
||||
|
||||
BIN
Media/HowItWorks1.jpg
Normal file
BIN
Media/HowItWorks1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
BIN
Media/HowItWorks2.jpg
Normal file
BIN
Media/HowItWorks2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
108
Readme.md
Normal file
108
Readme.md
Normal file
@ -0,0 +1,108 @@
|
||||
# BlurHash
|
||||
|
||||
BlurHash is a compact representation of a placeholder for an image.
|
||||
|
||||
## Why would you want this?
|
||||
|
||||
Does your designer cry every time you load their beautifully designed screen, and it is full of empty boxes because all the
|
||||
images have not loaded yet? Does your database engineer cry when you want to solve this by trying to cram little thumbnail
|
||||
images into your data to show as placeholders?
|
||||
|
||||
BlurHash will solve your problems! How? Like this:
|
||||
|
||||
## How does it work
|
||||
|
||||
In short, BlurHash takes an image, and gives you a short string (only 20-30 characters!) that represents the placeholder for this
|
||||
image. You would do this on the backend of your service, and store the string along the image. When you send data to your
|
||||
client, you send both the URL to the image, and the BlurHash string. Your client then takes the string, and decodes it into an
|
||||
image that it shows while the real image is loading over the network. The string is short enough that comfortably fits in with
|
||||
whatever data format you use. For instance, it can easily be added as a field in a JSON object.
|
||||
|
||||
In summary:
|
||||
|
||||

|
||||

|
||||
|
||||
Want to know all the gory technical details? Read the [algorithm description](Algorithm.md).
|
||||
|
||||
Implementing the algorithm is actually quite easy! Implementations are short and easily ported to your favourite language or
|
||||
platform.
|
||||
|
||||
## Implementations
|
||||
|
||||
So far, we have created these implementations:
|
||||
|
||||
* [C](C) - A simple encoder implemenation in portable C code.
|
||||
* [Swift](Swift) - Simple encoder and decoder implementations, and a larger library offering advanced features.
|
||||
There is also an example app to play around with the algorithm.
|
||||
* [Kotlin](Kotlin) - A simple decoder implementation for Android.
|
||||
* [TypeScript][TypeScript] - A simple decode implementation.
|
||||
* [Python](Python) - Integration of the C encoder code into Python.
|
||||
|
||||
## Contributing
|
||||
|
||||
We'd love contributions! The algorithm is [very simple](Algorithm.md) - less than two hundred lines of code - and can easily be
|
||||
ported to your platform of choice. And having support for more platforms would be wonderful! So, Java decoder? Golang encoder?
|
||||
Haskell? Rust? We want them all!
|
||||
|
||||
We will also try to tag any issues on our [issue tracker](..) that we'd love help with, so if you just want to dip in, go have a look.
|
||||
|
||||
You can file a pull request with us, or you can start your own repo and project if you want to run everything yourself, we don't mind.
|
||||
|
||||
If you do want to contribute to this project, we have a [code of conduct](CodeOfConduct.md).
|
||||
|
||||
## Good Questions
|
||||
|
||||
### How fast is encoding? Decoding?
|
||||
|
||||
The implementations here are not very optimised. Running them on very large images can be a bit slow. The performance of
|
||||
the encoder and decoder is about the same for the same input or output size, so decoding very large placeholders, especially
|
||||
on your UI thread, can be a bit slow.
|
||||
|
||||
However! The trick to using the algorithm correctly is to not run it on full-sized data. The fine detail of an image is all thrown away,
|
||||
so you should scale your images down before running BlurHash on them. If you are creating thumbnails, run BlurHash on those
|
||||
instead of the full images.
|
||||
|
||||
Similarly, when displaying the placeholders, very small images scaled work very well. We usually decode placeholders that are
|
||||
32 or even 20 pixels wide, and then let the UI layer scale them up, which is indistinguishable from decoding them at full size.
|
||||
|
||||
### How do I pick the number of X and Y components?
|
||||
|
||||
It depends a bit on taste. The more components you pick, the more information is retained in the placeholder, but the longer
|
||||
the BlurHash string will be. Also, it doesn't always look good with too many components. We usually go with 4 by 3, which
|
||||
seems to strike a nice balance.
|
||||
|
||||
However, you should adjust the number of components depending on the aspect ratio of your images. For instance, very wide
|
||||
images should have more X components and fewer Y components.
|
||||
|
||||
## Authors
|
||||
|
||||
* [Dag Ågren](https://github.com/DagAgren) - Original algorithm design, Swift and C implementations
|
||||
* [Mykhailo Shchurov](https://github.com/shchurov) - Kotlin decoder implementation
|
||||
* [Olli Mahlamäki](https://github.com/omahlama) - TypeScript decoder implemenation
|
||||
* [Atte Lautanala](https://github.com/lautat) - Python integration
|
||||
* _Your name here?_
|
||||
|
||||
## License
|
||||
|
||||
All of these implemenations are licensed under the MIT license:
|
||||
|
||||
Copyright (c) 2018 Wolt Enterprises
|
||||
|
||||
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.
|
||||
@ -123,6 +123,13 @@
|
||||
1BEFFFBE20BEE66400187F3F /* base83.ts */ = {isa = PBXFileReference; explicitFileType = sourcecode.javascript; path = base83.ts; sourceTree = "<group>"; };
|
||||
1BEFFFBF20BFDC1600187F3F /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
|
||||
1BEFFFC120BFE05600187F3F /* BlurHashDecoder.kt */ = {isa = PBXFileReference; lastKnownFileType = text; path = BlurHashDecoder.kt; sourceTree = "<group>"; };
|
||||
1BEFFFC220BFE33E00187F3F /* Readme.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Readme.md; sourceTree = "<group>"; };
|
||||
1BEFFFC320BFE34800187F3F /* Readme.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = Readme.md; path = ../Readme.md; sourceTree = "<group>"; };
|
||||
1BEFFFC420BFE35300187F3F /* Readme.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Readme.md; sourceTree = "<group>"; };
|
||||
1BEFFFC520BFE35D00187F3F /* Readme.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Readme.md; sourceTree = "<group>"; };
|
||||
1BEFFFC620BFF7B100187F3F /* Algorithm.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = Algorithm.md; path = ../Algorithm.md; sourceTree = "<group>"; };
|
||||
1BEFFFC720BFF7B100187F3F /* CodeOfConduct.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = CodeOfConduct.md; path = ../CodeOfConduct.md; sourceTree = "<group>"; };
|
||||
1BEFFFC820C000DE00187F3F /* License.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = License.txt; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -223,7 +230,11 @@
|
||||
1BEFFFC020BFE05600187F3F /* Kotlin */,
|
||||
1B2BA1CD1F0F7AF3006057C1 /* Ruby */,
|
||||
1B2BA1D31F0F8A64006057C1 /* Python */,
|
||||
1BEFFFA420BEE66400187F3F /* Typescript */,
|
||||
1BEFFFA420BEE66400187F3F /* TypeScript */,
|
||||
1BEFFFC620BFF7B100187F3F /* Algorithm.md */,
|
||||
1BEFFFC720BFF7B100187F3F /* CodeOfConduct.md */,
|
||||
1BEFFFC820C000DE00187F3F /* License.txt */,
|
||||
1BEFFFC320BFE34800187F3F /* Readme.md */,
|
||||
1B49CD1C1EC4721A006F8E7D /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
@ -245,6 +256,7 @@
|
||||
1BAA606F1FF40A1E00E42DD7 /* BlurHashKit */,
|
||||
1B49CD261EC47243006F8E7D /* BlurHashEncode.swift */,
|
||||
1B49CD281EC4724C006F8E7D /* BlurHashDecode.swift */,
|
||||
1BEFFFC420BFE35300187F3F /* Readme.md */,
|
||||
);
|
||||
name = Swift;
|
||||
sourceTree = "<group>";
|
||||
@ -267,7 +279,7 @@
|
||||
path = BlurHashKit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1BEFFFA420BEE66400187F3F /* Typescript */ = {
|
||||
1BEFFFA420BEE66400187F3F /* TypeScript */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BEFFFA620BEE66400187F3F /* demo */,
|
||||
@ -275,9 +287,10 @@
|
||||
1BEFFFB520BEE66400187F3F /* webpack.config.js */,
|
||||
1BEFFFB720BEE66400187F3F /* package.json */,
|
||||
1BEFFFB820BEE66400187F3F /* tsconfig.json */,
|
||||
1BEFFFC520BFE35D00187F3F /* Readme.md */,
|
||||
);
|
||||
name = Typescript;
|
||||
path = ../Typescript;
|
||||
name = TypeScript;
|
||||
path = ../TypeScript;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1BEFFFA620BEE66400187F3F /* demo */ = {
|
||||
@ -304,6 +317,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BEFFFC120BFE05600187F3F /* BlurHashDecoder.kt */,
|
||||
1BEFFFC220BFE33E00187F3F /* Readme.md */,
|
||||
);
|
||||
name = Kotlin;
|
||||
path = ../Kotlin;
|
||||
|
||||
19
Swift/License.txt
Normal file
19
Swift/License.txt
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2018 Wolt Enterprises
|
||||
|
||||
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.
|
||||
3
Swift/Readme.md
Normal file
3
Swift/Readme.md
Normal file
@ -0,0 +1,3 @@
|
||||
# BlurHash for iOS, in Swift
|
||||
|
||||
|
||||
1
TypeScript/Readme.md
Normal file
1
TypeScript/Readme.md
Normal file
@ -0,0 +1 @@
|
||||
# BlurHash in TypeScript
|
||||
Loading…
Reference in New Issue
Block a user