Created
March 10, 2020 10:13
Using orientation to flip image in Ionic 4
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
onFileChosen(event: Event) { | |
const pickedFile = (event.target as HTMLInputElement).files[0]; | |
if (!pickedFile) { | |
return; | |
} | |
let originalOrientation = 1; | |
ImageHelper.getOrientation(pickedFile, (orientation) => { | |
console.log('Orientation', orientation); | |
originalOrientation = orientation; | |
const fr = new FileReader(); | |
fr.onload = () => { | |
const dataUrl = fr.result.toString(); | |
this.manipulateImage(dataUrl, originalOrientation, pickedFile.name); | |
}; | |
fr.readAsDataURL(pickedFile); | |
}); | |
} | |
private manipulateImage(dataUrl: string, originalOrientation: number, imageName?: string) { | |
ImageHelper.resizeAndResetOrientation(dataUrl, originalOrientation, NEEDED_WIDTH, (fixedDataUrl) => { | |
this.selectedImage = fixedDataUrl; | |
const transformedFile = ImageHelper.dataURLtoFile(fixedDataUrl, ImageHelper.getImageName(imageName, 'some-random-file.jpg')); | |
this.imagePick.emit(transformedFile); | |
}); | |
} |
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 { Observable, Observer } from 'rxjs'; | |
export class ImageHelper { | |
public static getOrientation(file, callback) { | |
const reader = new FileReader(); | |
reader.onload = (event) => { | |
const view = new DataView((event.target as any).result as ArrayBuffer); | |
if (view.getUint16(0, false) !== 0xFFD8) { return callback(-2); } | |
const length = view.byteLength; | |
let offset = 2; | |
while (offset < length) { | |
const marker = view.getUint16(offset, false); | |
offset += 2; | |
if (marker === 0xFFE1) { | |
if (view.getUint32(offset += 2, false) !== 0x45786966) { | |
return callback(-1); | |
} | |
const little = view.getUint16(offset += 6, false) === 0x4949; | |
offset += view.getUint32(offset + 4, little); | |
const tags = view.getUint16(offset, little); | |
offset += 2; | |
for (let i = 0; i < tags; i++) { | |
if (view.getUint16(offset + (i * 12), little) === 0x0112) { | |
return callback(view.getUint16(offset + (i * 12) + 8, little)); | |
} | |
} | |
} else if ((marker & 0xFF00) !== 0xFF00) { break; } else { offset += view.getUint16(offset, false); } | |
} | |
return callback(-1); | |
}; | |
reader.readAsArrayBuffer(file.slice(0, 64 * 1024)); | |
} | |
public static getOrientationFromBase64(srcBase64, callback) { | |
const file = this.dataURLtoFile(srcBase64, 'some-random-name.jpg'); | |
const reader = new FileReader(); | |
reader.onload = (event) => { | |
const view = new DataView((event.target as any).result); | |
if (view.getUint16(0, false) !== 0xFFD8) { return callback(-2); } | |
const length = view.byteLength; | |
let offset = 2; | |
while (offset < length) { | |
const marker = view.getUint16(offset, false); | |
offset += 2; | |
if (marker === 0xFFE1) { | |
if (view.getUint32(offset += 2, false) !== 0x45786966) { | |
return callback(-1); | |
} | |
const little = view.getUint16(offset += 6, false) === 0x4949; | |
offset += view.getUint32(offset + 4, little); | |
const tags = view.getUint16(offset, little); | |
offset += 2; | |
for (let i = 0; i < tags; i++) { | |
if (view.getUint16(offset + (i * 12), little) === 0x0112) { | |
return callback(view.getUint16(offset + (i * 12) + 8, little)); | |
} | |
} | |
} else if ((marker & 0xFF00) !== 0xFF00) { break; } else { offset += view.getUint16(offset, false); } | |
} | |
return callback(-1); | |
}; | |
reader.readAsArrayBuffer(file.slice(0, 64 * 1024)); | |
} | |
public static dataURLtoFile(dataurl, filename: string) { | |
const arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], | |
bstr = atob(arr[1]); | |
let n = bstr.length; | |
const u8arr = new Uint8Array(n); | |
while (n--) { | |
u8arr[n] = bstr.charCodeAt(n); | |
} | |
return new File([u8arr], filename, { type: mime }); | |
} | |
public static resizeAndResetOrientation(srcBase64, srcOrientation, desiredWidth: number, callback) { | |
const img = new Image(); | |
img.onload = () => { | |
let divideFactor = 1; | |
if (img.width > desiredWidth) { | |
divideFactor = desiredWidth / img.width; | |
} | |
const width = img.width * divideFactor, | |
height = img.height * divideFactor, | |
canvas = document.createElement('canvas'), | |
ctx = canvas.getContext('2d'); | |
// set proper canvas dimensions before transform & export | |
if (4 < srcOrientation && srcOrientation < 9) { | |
canvas.width = height; | |
canvas.height = width; | |
} else { | |
canvas.width = width; | |
canvas.height = height; | |
} | |
// transform context before drawing image | |
switch (srcOrientation) { | |
case 2: ctx.transform(-1, 0, 0, 1, width, 0); break; | |
case 3: ctx.transform(-1, 0, 0, -1, width, height); break; | |
case 4: ctx.transform(1, 0, 0, -1, 0, height); break; | |
case 5: ctx.transform(0, 1, 1, 0, 0, 0); break; | |
case 6: ctx.transform(0, 1, -1, 0, height, 0); break; | |
case 7: ctx.transform(0, -1, -1, 0, height, width); break; | |
case 8: ctx.transform(0, -1, 1, 0, 0, width); break; | |
default: break; | |
} | |
// draw image | |
ctx.drawImage(img, 0, 0, img.width * divideFactor, img.height * divideFactor); | |
// export base64 | |
callback(canvas.toDataURL('image/jpeg')); | |
}; | |
img.src = srcBase64; | |
} | |
public static getImageName(imageName: string, name: string) { | |
return !!imageName ? imageName : name; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment