Last active
April 24, 2020 03:16
-
-
Save Snesi/a20a0fd298c6c32598644353edf2eb7f to your computer and use it in GitHub Desktop.
Angular 2+ Pipe that auto-rotate images locally in the browser by parsing exif data in pipe inspired by https://gist.github.com/runeb/c11f864cd7ead969a5f0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Pipe, PipeTransform } from '@angular/core' | |
import { SafeHtml, SafeStyle, SafeScript, SafeUrl, SafeResourceUrl, DomSanitizer } from '@angular/platform-browser' | |
import { Observable } from 'rxjs/Observable' | |
import 'rxjs/add/observable/bindcallback' | |
const rotation = { | |
1: 'rotate(0deg)', | |
3: 'rotate(180deg)', | |
6: 'rotate(90deg)', | |
8: 'rotate(270deg)' | |
} | |
const arrayBufferToBase64 = ( buffer ) => { | |
let binary = '' | |
const bytes = new Uint8Array( buffer ) | |
const len = bytes.byteLength; | |
for (let i = 0; i < len; i++) { | |
binary += String.fromCharCode( bytes[ i ] ) | |
} | |
return window.btoa( binary ) | |
} | |
@Pipe({ | |
name: 'rotationCorrection' | |
}) | |
export class RotationCorrectionPipe implements PipeTransform { | |
constructor() {} | |
public transform(image: Blob): Observable<string> { | |
const orientation = Observable.bindCallback<string>(this.orientation) | |
return orientation(image) | |
} | |
// Exif orientation value to css transform mapping | |
// Does not include flipped orientations | |
orientation(file, callback) { | |
const fileReader = new FileReader() | |
fileReader.onloadend = function() { | |
const base64img = 'data:' + file.type + ';base64,' + arrayBufferToBase64(fileReader.result) | |
const scanner = new DataView(fileReader.result) | |
let idx = 0 | |
let value = 1 // Non-rotated is the default | |
if (fileReader.result.length < 2 || scanner.getUint16(idx) !== 0xFFD8) { | |
// Not a JPEG | |
if (callback) { | |
callback(rotation[value]) | |
} | |
return | |
} | |
idx += 2 | |
let maxBytes = scanner.byteLength | |
while (idx < maxBytes - 2) { | |
const uint16 = scanner.getUint16(idx) | |
idx += 2 | |
switch (uint16) { | |
case 0xFFE1: // Start of EXIF | |
const exifLength = scanner.getUint16(idx) | |
maxBytes = exifLength - idx | |
idx += 2 | |
break | |
case 0x0112: // Orientation tag | |
// Read the value, its 6 bytes further out | |
// See page 102 at the following URL | |
// http://www.kodak.com/global/plugins/acrobat/en/service/digCam/exifStandard2.pdf | |
value = scanner.getUint16(idx + 6, false) | |
maxBytes = 0 // Stop scanning | |
break | |
} | |
} | |
if (callback) { | |
callback(rotation[value]) | |
} | |
} | |
fileReader.readAsArrayBuffer(file) | |
} | |
} |
How to use this pipe in html template .. can i have example of it.
i tried with adding this with image tags photoBlob | rotationCorrection | async.
but did not worked
Thanks for the gist! It helped me a lot.
Anyhow this only returns the rotate(xdeg) command, but the base64img variable is only created initially but never used again.
I am not an expert, but I guess this is either unused or (compared to the plain JS inspiration) not finished :)
Thank you anyways though!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Needs to be used in combination with async pipe like so:
photoBlob | rotationCorrection | async