diff --git a/dist/all.js b/dist/all.js
index 5181cef..a621381 100644
--- a/dist/all.js
+++ b/dist/all.js
@@ -2881,6 +2881,8 @@ e=a[0],c=a[2]):(d=a[2],e=a[0],c=a[1]);if(0>function(a,b,c){var d=b.x;b=b.y;retur
}
},
dragstart: function dragstart(event) {
+ if (event.altKey) return;
+
if (event.target.localName === 'img') {
event.preventDefault();
}
@@ -2898,6 +2900,7 @@ e=a[0],c=a[2]):(d=a[2],e=a[0],c=a[1]);if(0>function(a,b,c){var d=b.x;b=b.y;retur
return;
} // Prevent default behaviours as page zooming in touch devices.
+ if (event.altKey) return;
event.preventDefault();
@@ -4868,2300 +4871,2300 @@ function Y(){D=!1;if(document.fullscreen||document.fullscreenElement||document.w
g.move=function(a,b,c){a||0===a?c||(this.x=a?a=T(a,K-this.left-this.right,this.width):0,this.y=b?b=T(b,P-this.top-this.bottom,this.height):0):(a=this.x,b=this.y,this.l&&(0===a?this.resize(K/2,P):a===K-this.width&&this.resize(K/2,P)));n(this.g,"transform","translate("+a+"px,"+b+"px)");this.onmove&&this.onmove(a,b);return this};
g.resize=function(a,b,c){a||0===a?c||(this.width=a?a=T(a,K-this.left-this.right):0,this.height=b?b=T(b,P-this.top-this.bottom):0):(a=this.width,b=this.height);a=Math.max(a,this.j);b=Math.max(b,this.i);n(this.g,"width",a+"px");n(this.g,"height",b+"px");this.onresize&&this.onresize(a,b);return this};g.addClass=function(a){this.g.classList.add(a);return this};g.removeClass=function(a){this.g.classList.remove(a);return this};window.WinBox=R;}).call(this);
-// run when scripts and styles are loaded
-chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
- if (request.type == 'injected') {
- chrome.storage.sync.get('settings', function (settings) {
- try {
- if (settings.settings) {
- init(settings)
- }
- } catch (e) {
- console.error('error while loading settings: ', e)
- }
- })
- }
-})
-
-let IS_PICKER_OPEN = false
-let IS_DETAILS_OPEN = false
-let IS_HELP_OPEN = false
-let IS_CROP_OPEN = false
-
-let viewer
-let isLocalFile = window.location.href.match(/(file:\/\/)/) ? true : false;
-let BACKGROUND_TYPE = 'blurred'
-let UPLOAD_SITE = 'imgbb'
-let ImgCanvas
-let isFlippedHorizontally = false
-let isFlippedVertically = false
-let IMGBB_TOKEN = '8be35a61597b285f9c95669fdc565b00'
-let IMGUR_TOKEN = '405d491c9e67e9f'
-let isKeypressEnabled = false
-let WINBOX_CLASSES = ['no-scrollbar', 'no-max', 'no-min', 'no-full', 'no-resize', 'no-animation']
-let ocrLangList = {
- Afrikaans: 'afr',
- Albanian: 'sqi',
- Amharic: 'amh',
- Arabic: 'ara',
- Armenian: 'hye',
- Azerbaijani: 'aze',
- Basque: 'eus',
- Belarusian: 'bel',
- Bengali: 'ben',
- Bosnian: 'bos',
- Bulgarian: 'bul',
- Burmese: 'mya',
- Catalan: 'cat',
- Cebuano: 'ceb',
- 'Chinese Simplified': 'chi_sim',
- 'Chinese Simplified (vertical)': 'chi_sim_vert',
- 'Chinese Traditional': 'chi_tra',
- 'Chinese Traditional (vertical)': 'chi_tra_vert',
- Corsican: 'cos',
- Croatian: 'hrv',
- Czech: 'ces',
- Danish: 'dan',
- Dutch: 'nld',
- English: 'eng',
- Esperanto: 'epo',
- Estonian: 'est',
- Filipino: 'fil',
- Finnish: 'fin',
- French: 'fra',
- Frisian: 'fry',
- Galician: 'glg',
- Georgian: 'kat',
- German: 'deu',
- Greek: 'ell',
- Gujarati: 'guj',
- Haitian: 'hat',
- Hebrew: 'heb',
- Hindi: 'hin',
- Hungarian: 'hun',
- Icelandic: 'isl',
- Indonesian: 'ind',
- Irish: 'gle',
- Italian: 'ita',
- Japanese: 'jpn',
- 'Japanese (vertical)': 'jpn_vert',
- Javanese: 'jav',
- Kannada: 'kan',
- Kazakh: 'kaz',
- Khmer: 'khm',
- Korean: 'kor',
- 'Korean (vertical)': 'kor_vert',
- Kurdish: 'kmr',
- Lao: 'lao',
- Latin: 'lat',
- Latvian: 'lav',
- Lithuanian: 'lit',
- Luxembourgish: 'ltz',
- Macedonian: 'mkd',
- Malay: 'msa',
- Malayalam: 'mal',
- Maltese: 'mlt',
- Maori: 'mri',
- Marathi: 'mar',
- Mongolian: 'mon',
- Nepali: 'nep',
- Norwegian: 'nor',
- Persian: 'fas',
- Polish: 'pol',
- Portuguese: 'por',
- Romanian: 'ron',
- Russian: 'rus',
- 'Scottish Gaelic': 'gla',
- Serbian: 'srp',
- Sindhi: 'snd',
- Sinhala: 'sin',
- Slovak: 'slk',
- Slovenian: 'slv',
- Spanish: 'spa',
- Sundanese: 'sun',
- Swahili: 'swa',
- Swedish: 'swe',
- Tajik: 'tgk',
- Tamil: 'tam',
- Telugu: 'tel',
- Thai: 'tha',
- Turkish: 'tur',
- Ukrainian: 'ukr',
- Urdu: 'urd',
- Uzbek: 'uzb',
- Vietnamese: 'vie',
- Welsh: 'cym',
- Yiddish: 'yid',
- Yoruba: 'yor'
-}
-let tippyData = [
- {
- type: 'zoom-in',
- text: 'Zoom In'
- },
- {
- type: 'zoom-out',
- text: 'Zoom Out'
- },
- {
- type: 'one-to-one',
- text: '1:1'
- },
- {
- type: 'reset',
- text: 'Reset'
- },
- {
- type: 'fit-to-screen',
- text: 'Fit to Screen'
- },
- {
- type: 'rotate-left',
- text: 'Rotate Left'
- },
- {
- type: 'rotate-right',
- text: 'Rotate Right'
- },
- {
- type: 'flip-horizontal',
- text: 'Flip Horizontal'
- },
- {
- type: 'flip-vertical',
- text: 'Flip Vertical'
- },
- {
- type: 'crop',
- text: 'Crop Image'
- },
- {
- type: 'download',
- text: 'Download'
- },
- {
- type: 'play',
- text: 'Fullscreen'
- },
- {
- type: 'details',
- text: 'Details'
- },
- {
- type: 'colorpicker',
- text: 'Color Picker'
- },
- {
- type: 'paint',
- text: 'Photo Editor'
- },
- {
- type: 'print',
- text: 'Print image'
- },
- {
- type: 'help',
- text: 'Help'
- },
- {
- type: 'theme',
- text: 'Toggle Theme'
- },
- {
- type: 'exit',
- text: 'Turn Off'
- },
- {
- type: 'upload',
- text: 'Upload Image'
- },
- {
- type: 'ocr',
- text: 'Extract Text'
- },
- {
- type: 'photopea',
- text: 'Edit in Photopea'
- },
- {
- type: 'tineye',
- text: 'Reverse Image Search'
- },
- {
- type: 'about',
- text: 'About'
- },
- {
- type: 'qr',
- text: 'QR Code Scanner'
- },
- {
- type: 'settings',
- text: 'Settings'
- }
-]
-
-// ~~~ Custom Shortcut Hotkeys Section ~~~ \\
-chrome.storage.sync.get("shortcutHotkeys", (shortcutHotkeys) => {
- const sc_sc = shortcutHotkeys.shortcutHotkeys;
-
- document.addEventListener("keydown", function (e) {
- let activeModifier;
- if (e.ctrlKey) {activeModifier = "mod";} else if (e.shiftKey) {activeModifier = "shift";} else if (e.altKey) {activeModifier = "alt";};
-
- if (!isKeypressEnabled) {
- // if shortcut toggle = on { set custom hotkey; activate shortcut}
- if (sc_sc.zoomInToggle === true) {
- const hotkeyMod = sc_sc.zoom_in_mod;
- const hotkeyKey = sc_sc.zoom_in_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- // uses the custom hotkey to execute the selected shortcut
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-zoom-in')[0].click();
- // prevent the default shortcut
- e.preventDefault();
- });
- }
-
- if (sc_sc.zoomOutToggle === true) {
- const hotkeyMod = sc_sc.zoom_out_mod;
- const hotkeyKey = sc_sc.zoom_out_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-zoom-out')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.oneToOneToggle === true) {
- const hotkeyMod = sc_sc.one_to_one_mod
- const hotkeyKey = sc_sc.one_to_one_key
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-one-to-one')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.resetToggle === true) {
- const hotkeyMod = sc_sc.reset_mod;
- const hotkeyKey = sc_sc.reset_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName("viewer-reset")[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.fitToScreenToggle === true) {
- const hotkeyMod = sc_sc.fit_to_screen_mod;
- const hotkeyKey = sc_sc.fit_to_screen_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-fit-to-screen')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.fullscreenToggle === true) {
- const hotkeyMod = sc_sc.fullscreen_mod;
- const hotkeyKey = sc_sc.fullscreen_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-play')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.rotateLeftToggle === true) {
- const hotkeyMod = sc_sc.rotate_left_mod;
- const hotkeyKey = sc_sc.rotate_left_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-rotate-left')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.rotateRightToggle === true) {
- const hotkeyMod = sc_sc.rotate_right_mod;
- const hotkeyKey = sc_sc.rotate_right_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-rotate-right')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.flipHorizontalToggle === true) {
- const hotkeyMod = sc_sc.flip_horizontal_mod;
- const hotkeyKey = sc_sc.flip_horizontal_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-flip-horizontal')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.flipVerticalToggle === true) {
- const hotkeyMod = sc_sc.flip_vertical_mod;
- const hotkeyKey = sc_sc.flip_vertical_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-flip-vertical')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.cropImageToggle === true) {
- const hotkeyMod = sc_sc.crop_mod;
- const hotkeyKey = sc_sc.crop_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-crop')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.photoEditorToggle === true) {
- const hotkeyMod = sc_sc.photo_editor_mod;
- const hotkeyKey = sc_sc.photo_editor_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-paint')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.downloadToggle === true) {
- const hotkeyMod = sc_sc.download_mod;
- const hotkeyKey = sc_sc.download_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-download')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.uploadImageToggle === true) {
- const hotkeyMod = sc_sc.upload_mod;
- const hotkeyKey = sc_sc.upload_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-upload')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.colorPickerToggle === true) {
- const hotkeyMod = sc_sc.color_picker_mod;
- const hotkeyKey = sc_sc.color_picker_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-colorpicker')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.detailsToggle === true) {
- const hotkeyMod = sc_sc.details_mod;
- const hotkeyKey = sc_sc.details_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-details')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.themeToggle === true) {
- const hotkeyMod = sc_sc.theme_mod;
- const hotkeyKey = sc_sc.theme_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-theme')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.printImageToggle === true) {
- const hotkeyMod = sc_sc.print_mod;
- const hotkeyKey = sc_sc.print_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-print')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.extractTextToggle === true) {
- const hotkeyMod = sc_sc.extract_text_mod;
- const hotkeyKey = sc_sc.extract_text_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-ocr')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.photopeaToggle === true) {
- const hotkeyMod = sc_sc.photopea_mod;
- const hotkeyKey = sc_sc.photopea_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-photopea')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.reverseSearchToggle === true) {
- const hotkeyMod = sc_sc.reverse_search_mod;
- const hotkeyKey = sc_sc.reverse_search_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-tineye')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.helpToggle === true) {
- const hotkeyMod = sc_sc.help_mod;
- const hotkeyKey = sc_sc.help_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-help')[0].click();
- e.preventDefault();
- });
- }
-
- if (sc_sc.turnOffToggle === true) {
- const hotkeyMod = sc_sc.turn_off_mod;
- const hotkeyKey = sc_sc.turn_off_key;
- const customHotkey = hotkeyMod + "+" + hotkeyKey;
-
- Mousetrap.bind(customHotkey, (e) => {
- document.getElementsByClassName('viewer-exit')[0].click();
- e.preventDefault();
- });
- }
-
- }
- });
-});
-
-
-
-
- // ~~~ Initializes the Extension ~~~ \\
-function init(settings) {
- BACKGROUND_TYPE = settings.settings.default_theme
- UPLOAD_SITE = settings.settings.upload_site
-
- // checks the zoom setting - if it's nulled, then the default is set to 0.1 (10%)
- settings.settings.zoom_ratio == null ? (settings.settings.zoom_ratio = 0.1) : (zoomSetting = settings.settings.zoom_ratio)
- zoomSetting = settings.settings.zoom_ratio
-
- let imgElement = document.getElementsByTagName('img')[0] // get img element
- // if img element is found
- if (imgElement) {
- let blurryDiv = document.createElement('div') // create blurry div
- blurryDiv.setAttribute('class', 'blurry-bg') // add class to blurry div
- imgElement.parentNode.insertBefore(blurryDiv, imgElement) // add before img element
-
- // init Viewer
- viewer = new Viewer(imgElement, {
- inline: false,
- loading: false,
- interval: 0,
- zoomable: true,
- transition: true,
- navbar: false,
- title: false,
- keyboard: false,
- backdrop: false, // prevent exit when click backdrop
- zoomRatio: zoomSetting,
- toolbar: {
- next: false,
- prev: false,
- zoomIn: settings.settings.zoomIn && {
- show: 1,
- size: 'large'
- },
- zoomOut: settings.settings.zoomOut && {
- show: 1,
- size: 'large'
- },
- reset: settings.settings.reset && {
- show: 1,
- size: 'large',
- click: function () {
- viewer.image.src = window.location.href
- viewer.reset()
- setTimeout(() => {
- if (settings.settings.toolbar_position === 'top') {
- viewer.move(0, 50)
- }
- }, 100)
- window.dispatchEvent(new Event('resize'))
- }
- },
- oneToOne: settings.settings.oneToOne && {
- show: 1,
- size: 'large'
- },
- fitToScreen: settings.settings.fitToScreen && {
- show: 1,
- size: 'large',
- click: function () {
- // Calculates a Zoom Ratio, based off of the Max & Default height/width
- let heightRatio = window.innerHeight / imgElement.naturalHeight;
- let widthRatio = window.innerWidth / imgElement.naturalWidth
-
- // Zooms to the Max Height & Centers the Image : if Zoomed Width > Max Width, scale to the Max Width instead
- if (imgElement.naturalWidth*heightRatio > window.innerWidth) {
- viewer.zoomTo(widthRatio, true);
- viewer.moveTo(0, (window.innerHeight - (imgElement.naturalHeight * widthRatio))/2);
- } else {
- viewer.zoomTo(heightRatio, true);
- viewer.moveTo((window.innerWidth - (imgElement.naturalWidth * heightRatio))/2, 0);
- }
- }
- },
- play: settings.settings.play && {
- show: 1,
- size: 'large',
- click: function () {
- viewer.image
- .requestFullscreen()
- .then(function () {
- // console.log('requestFullscreen success');
- })
- .catch(function (error) {
- console.error(error)
- })
- }
- },
- rotateLeft: settings.settings.rotateLeft && {
- show: 1,
- size: 'large'
- },
- rotateRight: settings.settings.rotateRight && {
- show: 1,
- size: 'large'
- },
- flipHorizontal: settings.settings.flipHorizontal && {
- show: 1,
- size: 'large'
- },
- flipVertical: settings.settings.flipVertical && {
- show: 1,
- size: 'large'
- },
- crop: settings.settings.crop && {
- show: 1,
- size: 'large',
- click: function () {
- if (!IS_CROP_OPEN) {
- IS_CROP_OPEN = true
- // reset viewer
- //viewer.reset();
- let reset = viewer.reset()
- setTimeout(() => {
- if (settings.settings.toolbar_position === 'top') {
- viewer.move(0, 50)
- }
- }, 100)
- if (reset) {
- crop(viewer, viewer.image.src, viewer.image.width, viewer.image.height)
- }
- }
- }
- },
- paint: settings.settings.paint && {
- show: isLocalFile ? 0 : 1,
- size: 'large',
- click: function () {
- isKeypressEnabled = true
- // create new winbox
- let winboxPaint = new WinBox('Photo Editor', {
- class: ['no-scrollbar', 'no-min', 'no-animation'],
- index: 9999,
- x: 'center',
- y: 'center',
- width: '90%',
- height: '90%',
- background: 'rgba(0,0,0,0.9)',
- html: `
`
- })
-
- winboxPaint.show()
-
- const config = {
- theme: {
- palette: {
- 'txt-primary': '#ffffff',
- 'txt-primary-invert': '#ffffff',
- // 'txt-secondary': '#ffffff',
- // 'txt-secondary-invert': '#ffffff',
- // 'txt-placeholder': '#ffffff',
- 'accent-primary': '#1E262C',
- 'accent-primary-hover': '#000000',
- 'accent-primary-active': '#000000',
- // 'accent-primary-disabled': '#ffffff',
- 'bg-primary': '#00000000' // canvas bg
- //'bg-primary-hover': '#000000',
- //'bg-primary-active': '#000000',
- //'bg-primary-0-5-opacity': '#ffffff',
- //'bg-secondary': '#ffffff',
- //'icons-primary': '#ffffff',
- //'icons-primary-opacity-0-6': '#ffffff',
- //'icons-secondary': '#ffffff',
- // 'btn-primary-text': '#ffffff',
- // 'btn-disabled-text': '#ffffff',
- // 'link-primary': '#ffffff',
- // 'link-hover': '#ffffff',
- // 'link-active': '#ffffff',
- // 'borders-primary': '#ffffff',
- // 'borders-secondary': '#ffffff',
- // 'borders-strong': '#ffffff',
- // 'borders-invert': '#ffffff',
- // 'border-active-bottom': '#ffffff',
- // 'active-secondary': '#ffffff',
- // 'active-secondary-hover': '#ffffff',
- // 'active-secondary-active': '#ffffff',
- // 'tag': '#ffffff',
- // 'error': '#ffffff',
- // 'success': '#ffffff',
- // 'warning': '#ffffff',
- // 'info': '#ffffff',
- // 'light-shadow': '#ffffff',
- }
- },
- onBeforeSave: function (imageFileInfo) {
- // prevent default behavior
- return false
- },
- onSave: function (imageData, imageDesignState) {
- console.log('~ imageDesignState', imageDesignState)
- console.log('~ imageData', imageData)
- let newImgBase64 = imageData.imageBase64
- let imgElements = document.getElementsByTagName('img')
- for (let elem of imgElements) {
- elem.src = newImgBase64
- }
- // trigger resize event in setTimeout
- setTimeout(function () {
- window.dispatchEvent(new Event('resize'))
- }, 100)
- showNotification('💾 Image saved successfully', '#ffffff', '#000000', settings)
- setTimeout(() => {
- if (settings.settings.toolbar_position === 'top') {
- viewer.move(0, 50)
- }
- }, 100)
- winboxPaint.close()
- },
- moreSaveOptions: [
- {
- label: 'Save as new file',
- onClick: (triggerSaveModal, triggerSave) =>
- triggerSaveModal((...args) => {
- let a = document.createElement('a')
- a.href = args[0].imageBase64
- a.download = args[0].fullName
- a.click()
-
- showNotification('💾 Image downloaded successfully', '#ffffff', '#000000', settings)
- })
- }
- ],
- source: viewer.image.src,
- //onSave: (editedImageObject, designState) => console.log('saved', editedImageObject, designState),
- annotationsCommon: {
- fill: '#ff0000'
- },
- Text: { text: 'Your Text Here...' },
- translations: {
- profile: 'Profile',
- coverPhoto: 'Cover photo',
- facebook: 'Facebook',
- socialMedia: 'Social Media',
- fbProfileSize: '180x180px',
- fbCoverPhotoSize: '820x312px'
- },
- Crop: {
- presetsItems: [
- {
- titleKey: 'classicTv',
- descriptionKey: '4:3',
- ratio: 4 / 3
- // icon: CropClassicTv, // optional, CropClassicTv is a React Function component. Possible (React Function component, string or HTML Element)
- },
- {
- titleKey: 'cinemascope',
- descriptionKey: '21:9',
- ratio: 21 / 9
- // icon: CropCinemaScope, // optional, CropCinemaScope is a React Function component. Possible (React Function component, string or HTML Element)
- }
- ],
- presetsFolders: [
- {
- titleKey: 'socialMedia', // will be translated into Social Media as backend contains this translation key
- // icon: Social, // optional, Social is a React Function component. Possible (React Function component, string or HTML Element)
- groups: [
- {
- titleKey: 'facebook',
- items: [
- {
- titleKey: 'profile',
- width: 180,
- height: 180,
- descriptionKey: 'fbProfileSize'
- },
- {
- titleKey: 'coverPhoto',
- width: 820,
- height: 312,
- descriptionKey: 'fbCoverPhotoSize'
- }
- ]
- }
- ]
- }
- ]
- },
- tabsIds: [window.FilerobotImageEditor.TABS.ADJUST, window.FilerobotImageEditor.TABS.ANNOTATE, window.FilerobotImageEditor.TABS.WATERMARK, window.FilerobotImageEditor.TABS.FILTERS, window.FilerobotImageEditor.TABS.FINETUNE, window.FilerobotImageEditor.TABS.RESIZE], // or ['Adjust', 'Annotate', 'Watermark']
- defaultTabId: window.FilerobotImageEditor.TABS.ANNOTATE, // or 'Annotate'
- defaultToolId: window.FilerobotImageEditor.TOOLS.TEXT // or 'Text'
- }
-
- console.log(window.FilerobotImageEditor.TABS)
-
- // Assuming we have a div with id="editor_container"
- const filerobotImageEditor = new FilerobotImageEditor(document.querySelector('#paint-wrapper'), config)
-
- filerobotImageEditor.render({
- onClose: closingReason => {
- console.log('Closing reason', closingReason)
- filerobotImageEditor.terminate()
- }
- })
-
- // window.p = Painterro({
- // hideByEsc: true,
- // saveByEnter: true,
- // hiddenTools: [
- // 'open', 'close', 'resize', 'eraser'
- // ],
- // id: 'paint-wrapper',
- // availableLineWidths: [1, 2, 4, 8, 16, 64],
- // availableEraserWidths: [1, 2, 4, 8, 16, 64],
- // availableFontSizes: [1, 2, 4, 8, 16, 64],
- // availableArrowLengths: [10, 20, 30, 40, 50, 60],
- // defaultTool: 'brush',
- // saveHandler: (image, done) => {
-
- // let newImgBase64 = image.asDataURL();
-
- // let imgElements = document.getElementsByTagName('img');
- // // loop through all img elements
- // // for (let i = 0; i < imgElements.length; i++) {
- // // // replace image with cropped image
- // // imgElements[i].src = newImgBase64;
- // // }
-
- // for (let elem of imgElements) {
- // elem.src = newImgBase64;
- // }
-
- // // trigger resize event in setTimeout
- // setTimeout(function () {
- // window.dispatchEvent(new Event('resize'));
- // }, 100);
-
- // showNotification('💾 Image saved successfully', '#ffffff', '#000000', settings);
- // setTimeout(() => {
- // if (settings.settings.toolbar_position === 'top') {
- // viewer.move(0, 50);
- // }
- // }, 100);
-
- // winboxPaint.close();
- // done(true);
- // }
- // }).show(viewer.image.src);
- }
- },
- download: settings.settings.download && {
- show: isLocalFile ? 0 : 1,
- size: 'large',
- click: function () {
- download(viewer.image)
- }
- },
- upload: settings.settings.upload && {
- show: isLocalFile ? 0 : 1,
- size: 'large',
- click: function () {
- let uriString = getBase64Image(viewer.image)
-
- // get base64 part from string
- let base64 = uriString.split(',')[1]
-
- // create html element with text
- let x = document.createElement('div')
- // set flex
- x.style.display = 'flex'
- // set element inner html
- x.innerHTML = ` Uploading image... Please wait`
-
- Toastify({
- node: x,
- duration: 999999,
- newWindow: true,
- close: false,
- gravity: settings.settings.notification_gravity, // `top` or `bottom`
- position: settings.settings.notification_position, // `left`, `center` or `right`
- stopOnFocus: true, // Prevents dismissing of toast on hover
- style: {
- color: '#ffffff',
- background: '#000000'
- }
- //onClick: function () { } // Callback after click
- }).showToast()
-
- // upload image to either imgbb or imgur, depending on the current setting
- switch (UPLOAD_SITE) {
- // upload to imgbb
- case 'imgbb':
- let formdata = new FormData()
- formdata.append('image', base64)
-
- let requestOptionsIMGBB = {
- method: 'POST',
- body: formdata,
- redirect: 'follow'
- }
-
- fetch(`https://api.imgbb.com/1/upload?expiration=600&key=${IMGBB_TOKEN}`, requestOptionsIMGBB)
- .then(res => res.json())
- .then(res => {
- // remove toast
- let toastifyElems = document.querySelectorAll('.toastify')
- toastifyElems.forEach(element => {
- element.remove()
- })
-
- copyToClipboard(res.data.image.url)
- showNotification('✔️ Image uploaded successfully', '#ffffff', '#000000', settings)
- showNotification(`📋 URL copied to clipboard`, '#ffffff', '#000000', settings)
- })
- break
- // upload to imgur
- case 'imgur':
- let requestOptionsIMGUR = {
- method: 'POST',
- headers: { 'Authorization': `Client-ID ${IMGUR_TOKEN}` },
- body: base64
- }
-
- fetch('https://api.imgur.com/3/image', requestOptionsIMGUR)
- .then(res => res.json())
- .then((res) => {
- // remove toast
- let toastifyElems = document.querySelectorAll('.toastify');
- toastifyElems.forEach(element => {
- element.remove()
- });
-
- copyToClipboard(res.data.link);
- showNotification('✔️ Image uploaded successfully', '#ffffff', '#000000', settings)
- showNotification(`📋 URL copied to clipboard`, '#ffffff', '#000000', settings)
- });
- break
- }
- }
- },
- colorpicker: settings.settings.colorpicker && {
- show: isLocalFile ? 0 : 1,
- size: 'large',
- click: async function () {
- if (!IS_PICKER_OPEN) {
- IS_PICKER_OPEN = true
-
- // change cursor to picker
- viewer.image.style.cursor = 'crosshair'
-
- let colorPickerBox = new WinBox('Color Preview', {
- class: WINBOX_CLASSES,
- background: 'rgba(0,0,0,0.9)',
- index: 9999,
- width: '250px',
- height: '250px',
- y: 'bottom',
- x: '10px',
- html: `
- `,
- onclose: function () {
- IS_PICKER_OPEN = false
- // change cursor back to default
- viewer.image.style.cursor = 'default'
- viewer.image.click() // trigger a click to remove the event listener
- }
- })
-
- // init color picker
- const pickr = Pickr.create({
- el: '.color-picker',
- inline: true,
- showAlways: true,
- theme: 'classic', // or 'monolith', or 'nano'
- useAsButton: false,
- autoReposition: true,
- appClass: 'color-picker-app',
- components: {
- // Main components
- preview: true,
- opacity: false,
- hue: true,
-
- // Input / output Options
- interaction: {
- hex: true,
- rgba: true,
- hsla: true,
- hsva: true,
- cmyk: true,
- input: true
- }
- }
- })
-
- // auto size window
- let contentWidth = document.getElementsByClassName('pcr-app')[0].getBoundingClientRect().width
- let contentHeight = document.getElementsByClassName('pcr-app')[0].getBoundingClientRect().height
- colorPickerBox.resize(contentWidth + 8, contentHeight + 35) // TODO: use better way to get content height and width
- colorPickerBox.show()
-
- // create new canvas
- let canvas = document.createElement('canvas')
- canvas.style.display = 'none'
-
- let x = ''
- let y = ''
-
- // when image clicked
- viewer.image.addEventListener(
- 'click',
- function (e) {
- if (IS_PICKER_OPEN) {
- handleImageClickOnPicker(e, viewer, canvas, pickr, x, y, settings)
- } else {
- this.removeEventListener('click', arguments.callee)
- }
- },
- false
- )
-
- // when mouse move
- viewer.image.addEventListener(
- 'mousemove',
- function (e) {
- if (IS_PICKER_OPEN) {
- handleMouseMoveOnPicker(e, viewer, canvas, pickr, x, y)
- } else {
- this.removeEventListener('mousemove', arguments.callee)
- }
- },
- false
- )
- } else {
- return
- }
- }
- },
- details: settings.settings.details && {
- show: isLocalFile ? 0 : 1,
- size: 'large',
- click: async function () {
- if (!IS_DETAILS_OPEN) {
- IS_DETAILS_OPEN = true
- try {
- new WinBox('Details', {
- class: [
- //"no-scrollbar",
- 'no-max',
- 'no-min',
- 'no-full',
- 'no-resize',
- 'no-animation'
- ],
- index: 9999,
- background: 'rgba(0,0,0,0.9)',
- x: '20px',
- y: '20px',
- width: '350px',
- height: '40%',
- html: ``,
- onclose: function () {
- IS_DETAILS_OPEN = false
- }
- })
- } catch (error) {
- console.error(error)
- }
- }
-
- let img2 = viewer.image
-
- const fileImg = await fetch(img2.src).then(r => r.blob())
- let fileSizeMB = fileImg.size / 1024 / 1024
-
- let imgDetails = {
- width: img2.naturalWidth,
- height: img2.naturalHeight,
- filesize: fileSizeMB.toFixed(2) + ' MB'
- }
-
- EXIF.getData(img2, function () {
- let allMetaData = EXIF.getAllTags(this)
- // add all metadata to wrapper
- // let wrapper = document.getElementById('details-wrapper');
-
- delete allMetaData.ImageWidth
- delete allMetaData.ImageHeight
- delete allMetaData.thumbnail
-
- allMetaData = { Width: imgDetails.width + 'px', Height: imgDetails.height + 'px', 'File size': imgDetails.filesize, ...allMetaData }
-
- let el = document.querySelector('#details-wrapper')
- el.innerHTML = jsonViewer(allMetaData, true)
-
- // convert to string
- //let metaDataString = JSON.stringify(allMetaData, null, "\t");
-
- // add string inside wrapper
- //wrapper.innerHTML = metaDataString;
- })
- }
- },
- theme: settings.settings.theme && {
- show: 1,
- size: 'large',
- click: function () {
- // blur --> light --> dark
- changeTheme(viewer.image.src, settings)
- }
- },
- print: settings.settings.print && {
- show: isLocalFile ? 0 : 1,
- size: 'large',
- click: function () {
- printImage(viewer.image)
- }
- },
- ocr: settings.settings.ocr && {
- show: 1,
- size: 'large',
- click: function () {
- let v = viewer
- let url = viewer.image.src
- let width = viewer.image.width
- let height = viewer.image.height
-
- let ocrPreviewBox = new WinBox('Image To Text: Select Region', {
- id: 'ocr-preview',
- class: WINBOX_CLASSES,
- modal: false,
- index: 9999,
- x: 'center',
- y: 'center',
- width: width + 7,
- height: height + 40,
- background: 'rgba(0,0,0,0.9)',
- html: ``,
- onclose: function () {
- document.querySelector('#ocr-preview').remove()
- document.querySelector('#ocr-settings').remove()
- }
- })
- ocrPreviewBox.show()
- let ocrControlBox = new WinBox('Image To Text: Settings', {
- id: 'ocr-settings',
- class: WINBOX_CLASSES,
- modal: false,
- index: 9999,
- x: '10px',
- y: 'bottom',
- top: '10px',
- bottom: '10px',
- right: '10px',
- left: '10px',
- width: '250px',
- height: '160px',
- background: 'rgba(0,0,0,0.9)',
- html: `
-
-
Select Language
-
-
-
-
-
-
`,
- onclose: function () {
- document.querySelector('#ocr-preview').remove()
- document.querySelector('#ocr-settings').remove()
- document.querySelector('#ocr-result-box').remove()
- }
- })
- ocrControlBox.show()
- let imgCropper = tinycrop.create({
- parent: '#parent-crop',
- image: url,
- bounds: {
- width: width,
- height: height
- },
- backgroundColors: ['#fff', '#f3f3f3'],
- selection: {
- color: '#212121CC',
- activeColor: '#ff0000CC',
- minWidth: 10,
- minHeight: 10,
- x: v.image.naturalWidth / 2 - width / 2,
- y: v.image.naturalHeight / 2 - height / 2,
- width: width,
- height: height
- },
- onInit: () => {
- console.log('Initialised')
- }
- })
-
- let region // contains the cropped region
- imgCropper.on('change', r => {
- region = r
- })
-
- Object.keys(ocrLangList).forEach(function (key) {
- let option = document.createElement('option')
- option.value = ocrLangList[key]
- option.text = key
- if (key == 'English') {
- option.selected = true
- }
- document.querySelector('#ocr-languages').appendChild(option)
- })
- // when btn-extract-text clicked
- document.getElementById('btn-extract-text').addEventListener('click', function () {
- // get selected language
- let selectedLang = document.querySelector('#ocr-languages').value
-
- const cropRect = region
- const canvas = document.createElement('canvas')
- const context = canvas.getContext('2d')
- const imageObj = new Image()
- canvas.width = cropRect.width
- canvas.height = cropRect.height
- imageObj.src = url
-
- imageObj.onload = function () {
- context.drawImage(imageObj, cropRect.x, cropRect.y, cropRect.width, cropRect.height, 0, 0, cropRect.width, cropRect.height)
- let ImgUrl = canvas.toDataURL()
-
- console.log(ImgUrl)
-
- // create html element with text
- let x = document.createElement('div')
- // set flex
- x.style.display = 'flex'
- // set element inner html
- x.innerHTML = ` Extracting Text`
-
- Toastify({
- node: x,
- duration: 999999,
- newWindow: true,
- close: false,
- gravity: settings.settings.notification_gravity, // `top` or `bottom`
- position: settings.settings.notification_position, // `left`, `center` or `right`
- stopOnFocus: true, // Prevents dismissing of toast on hover
- style: {
- color: '#ffffff',
- background: '#000000'
- }
- }).showToast()
-
- // tesseract to ocr
- Tesseract.recognize(ImgUrl, selectedLang, { logger: m => console.log(m) }).then(({ data: { text } }) => {
- // remove all toasts
- let toastifyElems = document.querySelectorAll('.toastify')
- toastifyElems.forEach(element => {
- element.remove()
- })
-
- let ocrResElem = document.querySelector('#ocr-textarea')
- if (ocrResElem) {
- // if exists, then update
- ocrResElem.innerHTML = text
- } else {
- // create new winbox
-
- document.querySelector('#ocr-preview').remove()
- document.querySelector('#ocr-settings').remove()
-
- let ocrResultBox = new WinBox('Result', {
- id: 'ocr-result-box',
- class: WINBOX_CLASSES,
- index: 9999,
- width: '500px',
- height: '320px',
- top: '10px',
- bottom: '10px',
- right: '10px',
- left: '10px',
- x: 'center',
- y: 'center',
-
- background: 'rgba(0,0,0,0.9)',
- html: `
-
-
-
`
- })
-
- ocrResultBox.show()
-
- // when btn-extract-text clicked
- document.getElementById('btn-copytext').addEventListener('click', function () {
- showNotification('📋 Copied to clipboard', '#ffffff', '#000000', settings)
- copyToClipboard(document.querySelector('#ocr-textarea').value)
- })
- }
- })
- }
- })
- try {
- } catch (error) {
- console.error(error)
- }
-
- // // for each key in object ocr
- // for (const [key, value] of Object.entries(ocrLangList)) {
- // console.log(`${key}: ${value}`);
- // }
- }
- },
- photopea: settings.settings.photopea && {
- show: isLocalFile ? 0 : 1,
- size: 'large',
- click: function () {
- let currentUrl = window.location.href
- // create html element with text
- let x = document.createElement('div')
- // set flex
- x.style.display = 'flex'
- // set element inner html
- x.innerHTML = ` Opening in Photopea... Please wait`
-
- Toastify({
- node: x,
- duration: 999999,
- newWindow: true,
- close: false,
- gravity: settings.settings.notification_gravity, // `top` or `bottom`
- position: settings.settings.notification_position, // `left`, `center` or `right`
- stopOnFocus: true, // Prevents dismissing of toast on hover
- style: {
- color: '#ffffff',
- background: '#000000'
- }
- }).showToast()
-
- // upload image to imgbb
- // NB: expiration time is 60 seconds
- fetch(`https://api.imgbb.com/1/upload?expiration=60&key=${IMGBB_TOKEN}&image=${encodeURIComponent(currentUrl)}`)
- .then(res => res.json())
- .then(res => {
- const uri = '{ "files" : [ "' + res.data.image.url + '" ] }'
- const encoded = encodeURI(uri)
- const urlEncoded = 'https://www.photopea.com/#' + encoded
- // remove toast
- let toastifyElems = document.querySelectorAll('.toastify')
- toastifyElems.forEach(element => {
- element.remove()
- })
-
- window.open(urlEncoded, '_blank').focus()
-
- showNotification(`📂 Image opened in Photopea successfully`, '#ffffff', '#000000', settings)
- })
- }
- },
- tineye: settings.settings.tineye && {
- show: isLocalFile ? 0 : 1,
- size: 'large',
- click: function () {
- // toastify
- let x = document.createElement('div')
- // set flex
- x.style.display = 'flex'
- // set element inner html
- x.innerHTML = ` Opening in TinEye... Please wait`
-
- Toastify({
- node: x,
- duration: 1000,
- newWindow: true,
- close: false,
- gravity: settings.settings.notification_gravity, // `top` or `bottom`
- position: settings.settings.notification_position, // `left`, `center` or `right`
- stopOnFocus: true, // Prevents dismissing of toast on hover
- style: {
- color: '#ffffff',
- background: '#000000'
- }
- }).showToast()
-
- setTimeout(function () {
- let currentUrl = encodeURIComponent(window.location.href)
- let action_url = 'http://tineye.com/search?url=' + currentUrl
- window.open(action_url, '_blank').focus()
- }, 1000)
- }
- },
- qr: settings.settings.qr && {
- show: isLocalFile ? 0 : 1,
- size: 'large',
- click: function () {
- // show loading toast
- let x = document.createElement('div')
- // set flex
- x.style.display = 'flex'
- // set element inner html
- x.innerHTML = ` Scanning QR code... Please wait`
-
- Toastify({
- node: x,
- duration: 9999,
- newWindow: true,
- close: false,
- gravity: settings.settings.notification_gravity, // `top` or `bottom`
- position: settings.settings.notification_position, // `left`, `center` or `right`
- stopOnFocus: true, // Prevents dismissing of toast on hover
- style: {
- color: '#ffffff',
- background: '#000000'
- }
- }).showToast()
-
- // remove loading toast
- setTimeout(function () {
- let toastifyElems = document.querySelectorAll('.toastify')
- toastifyElems.forEach(element => {
- element.remove()
- })
-
- qrcode.callback = function (res) {
- if (res instanceof Error) {
- showNotification(`❌ No QR code found.`, '#ffffff', '#000000', settings)
- } else {
- //alert(res);
- // show winbox
-
- let ocrResultBox = new WinBox('QR Code Result', {
- id: 'ocr-result-box',
- class: WINBOX_CLASSES,
- index: 9999,
- width: '500px',
- height: '165px',
- top: '10px',
- bottom: '10px',
- right: '10px',
- left: '10px',
- x: 'center',
- y: 'center',
- background: 'rgba(0,0,0,0.9)',
- html: `
-
-
-
-
`
- })
-
- ocrResultBox.show()
-
- // when btn-extract-text clicked
- document.getElementById('btn-copytext').addEventListener('click', function () {
- showNotification('📋 Copied to clipboard', '#ffffff', '#000000', settings)
- copyToClipboard(document.querySelector('#qr-textarea').value)
- })
- }
- }
- let b64Img = getBase64Image(viewer.image)
- qrcode.decode(b64Img)
- }, 500)
- }
- },
- help: settings.settings.help && {
- show: 1,
- size: 'large',
- click: function () {
- if (!IS_HELP_OPEN) {
- IS_HELP_OPEN = true
-
- try {
- new WinBox('Help', {
- class: WINBOX_CLASSES,
- index: 9999,
- x: 'center',
- y: 'center',
- top: '10px',
- bottom: '10px',
- right: '10px',
- left: '10px',
- width: '700px',
- height: '423px',
- background: 'rgba(0,0,0,0.9)',
- url: 'https://www.youtube-nocookie.com/embed/3p7Jrdx2jOc?autoplay=1&color=white&controls=0&disablekb=1&loop=1&modestbranding=1&rel=0&mute=1',
- onclose: function () {
- IS_HELP_OPEN = false
- }
- })
-
- new WinBox('Shortcuts', {
- class: WINBOX_CLASSES,
- index: 9999,
- x: 'right',
- y: 'center',
- top: '10px',
- bottom: '10px',
- right: '10px',
- left: '10px',
- width: '550px',
- height: '90%',
- background: 'rgba(0,0,0,0.9)',
- url: chrome.runtime.getURL('pages/shortcuts.html'),
- onclose: function () {
- IS_HELP_OPEN = false
- }
- })
- } catch (error) {
- console.error(error)
- }
- }
- }
- },
- settings: settings.settings.settings && {
- show: 1,
- size: 'large',
- click: function () {
- // open winbox
- try {
- new WinBox('Settings', {
- class: WINBOX_CLASSES,
- index: 9999,
- x: 'center',
- y: 'center',
- top: '10px',
- bottom: '10px',
- right: '10px',
- left: '10px',
- width: '350px',
- height: '400px',
- background: 'rgba(0,0,0,0.9)',
- url: chrome.runtime.getURL('pages/settings.html')
- })
- } catch (error) {
- console.error(error)
- }
- }
- },
- about: settings.settings.about && {
- show: 1,
- size: 'large',
- click: function () {
- try {
- new WinBox('About', {
- class: WINBOX_CLASSES,
- index: 9999,
- x: 'center',
- y: 'center',
- width: '700px',
- height: '500px',
- background: 'rgba(0,0,0,0.9)',
- url: chrome.runtime.getURL('pages/about.html')
- })
- } catch (error) {
- console.error(error)
- }
- }
- },
- exit: settings.settings.exit && {
- show: 1,
- size: 'large',
- click: function () {
- let url = window.location.href
- viewer.destroy()
- document.querySelector('.blurry-bg').remove()
- document.querySelector('img').style.display = 'block'
- document.querySelectorAll('.winbox').forEach(function (el) {
- el.remove()
- })
- // remove all style tags
- let styleTags = document.querySelectorAll('style')
- styleTags.forEach(function (el) {
- el.remove()
- })
- document.querySelector('img').src = url
- }
- },
- more: {
- show: 1,
- size: 'large',
- click: function () {
- // get all viewer buttons
- let viewerButtons = document.querySelectorAll('div.viewer-toolbar > ul > li')
-
- let btnsExceptMore = Array.prototype.slice.call(viewerButtons).filter(function (el) {
- return !el.classList.contains('viewer-more')
- })
-
- btnsExceptMore.forEach(btn => {
- // toggle display of each button
-
- let cssObj = window.getComputedStyle(btn, null)
- let display = cssObj.getPropertyValue('display')
-
- if (display === 'none') {
- btn.style.display = 'list-item'
- btn.style.opacity = 1
- // append class
- btn.classList.add('fade-in-right')
- } else {
- btn.style.display = 'none'
- btn.style.opacity = 0
- }
- })
- }
- }
- },
- ready() {
- // hide all at start
- if (settings.settings.hide_all_at_start) {
- // get all viewer buttons
- let viewerButtons = document.querySelectorAll('div.viewer-toolbar > ul > li')
-
- let btnsExceptMore = Array.prototype.slice.call(viewerButtons).filter(function (el) {
- return !el.classList.contains('viewer-more')
- })
-
- btnsExceptMore.forEach(btn => {
- // toggle display of each button
-
- let cssObj = window.getComputedStyle(btn, null)
- let display = cssObj.getPropertyValue('display')
-
- if (display === 'none') {
- btn.style.display = 'list-item'
- btn.style.opacity = 1
- // append class
- btn.classList.add('fade-in-right')
- } else {
- btn.style.display = 'none'
- btn.style.opacity = 0
- }
- })
- }
-
- setTimeout(() => {
- if (settings.settings.toolbar_position === 'top') {
- viewer.move(0, 50)
- }
- }, 100)
- }
- })
-
- let lightTheme = `
- transition: all 0.5s ease;
- background-image: none;
- background-color: #ffffff;
- filter: blur(0px);
- -webkit-filter: blur(0px);
- height: 100%;
- background-position: center;
- background-repeat: no-repeat;
- background-size: cover;
- width: 100vw;
- height: 100vh;
- transform: scale(1.3);
- `
-
- let darktheme = `
- transition: all 0.5s ease;
- background-image: none;
- background-color: #0e1217;
- filter: blur(0px);
- -webkit-filter: blur(0px);
- height: 100%;
- background-position: center;
- background-repeat: no-repeat;
- background-size: cover;
- width: 100vw;
- height: 100vh;
- transform: scale(1.3);
- opacity: 0;
- `
-
- let blurrytheme = `
- transition: none;
- background-image: url(${imgElement.src});
- background-color: none;
- filter: blur(15px);
- -webkit-filter: blur(15px);
- height: 100%;
- background-position: center;
- background-repeat: no-repeat;
- background-size: cover;
- width: 100vw;
- height: 100vh;
- transform: scale(1.3);
- opacity: 1;
- `
-
- let currentTheme = bg => {
- if (bg === 'light') {
- return lightTheme
- } else if (bg === 'dark') {
- return darktheme
- }
- return blurrytheme
- }
-
- // inject css
- injectCSS(`
- .blurry-bg {
- ${currentTheme(BACKGROUND_TYPE)}
- }
- /* Make blur darker */
- .blurry-bg:before {
- content: '';
- background-color: #000;
- opacity: ${BACKGROUND_TYPE === 'blurred' ? 0.5 : 0};
- width: 100%;
- height: 100%;
- z-index: 1;
- position: absolute;
- top: 0;
- left: 0;
- }
- img{
- display: none
- }
- .viewer-footer {
- bottom: ${settings.settings.toolbar_position === 'bottom' ? '0px' : 'unset'} !important;
- top: ${settings.settings.toolbar_position === 'top' ? '10px' : 'unset'} !important;
- }
- `)
-
- // show the viewer
- viewer.show()
-
- setTippyText(tippyData)
- }
-}
-
-/**
- * Helper function - converts an svg element to a base64 string
- * @param {svgElement} svgElement the svg element to convert
- * @returns
- */
-function svgToBase64(svgElement) {
- let svgString = new XMLSerializer().serializeToString(svgElement)
- let decoded = unescape(encodeURIComponent(svgString))
- let base64 = btoa(decoded)
- return `data:image/svg+xml;base64,${base64}`
-}
-
-/**
- * Injects css into the page
- * @param {string} css string to inject
- * @returns
- */
-function injectCSS(css) {
- let head = document.getElementsByTagName('head')[0]
- if (!head) {
- return
- }
- let style = document.createElement('style')
- style.innerHTML = DOMPurify.sanitize(css)
- head.appendChild(style)
-}
-
-/**
- * tippy.js text - add tooltips to viewer's toolbar
- * @param {*} arrBtns array Of Buttons
- */
-function setTippyText(arrBtns) {
- window.tippyInstances = []
-
- arrBtns.forEach(function (item) {
- let instances = tippy(`#viewer0 > div.viewer-footer > div.viewer-toolbar > ul > li.viewer-${item.type}.viewer-large`, {
- content: item.text,
- inertia: true,
- animation: 'scale',
- theme: 'dark'
- })
- window.tippyInstances = tippyInstances.concat(instances)
- })
-}
-
-/**
- * Download image
- * @param {HTMLElement} image Viewer Image
- */
-function download(image) {
- const a = document.createElement('a')
- a.href = image.src
- a.download = image.alt
- document.body.appendChild(a)
- a.click()
- document.body.removeChild(a)
-}
-
-/**
- *
- * @param {viewer} viewer
- * @param {string} url
- * @param {*} width
- * @param {*} height
- */
-function crop(v, url, width, height) {
- // create new winbox
- let winbox = new WinBox('Crop Image', {
- id: 'winbox-crop-image',
- class: WINBOX_CLASSES,
-
- width: width + 7,
- // height + 10%
- height: height + 40 + 36,
- x: 'center',
- y: 'center',
- index: 9999,
- background: 'rgba(0,0,0,0.9)',
- html: `
-
-
- `,
- onclose: function () {
- // reset viewer zoom
- // v.zoom(0.5);
- IS_CROP_OPEN = false
- }
- })
-
- let imgCropper = tinycrop.create({
- parent: '#parent-crop',
- image: url,
- bounds: {
- width: width,
- height: height
- },
- backgroundColors: ['#fff', '#f3f3f3'],
- selection: {
- color: '#212121CC',
- activeColor: '#ff0000CC',
- minWidth: 10,
- minHeight: 10,
- x: v.image.naturalWidth / 2 - width / 2,
- y: v.image.naturalHeight / 2 - height / 2,
- width: width,
- height: height
- },
- onInit: () => {
- console.log('Initialised')
- }
- })
-
- let region // contains the cropped region
- imgCropper.on('change', r => {
- console.log('change', r)
- region = r
- })
-
- // const image = document.getElementById('crop-img');
-
- setTimeout(function () {
- // get crop btn and add event listener
- let cropBtn = document.getElementById('btn-crop-img')
-
- cropBtn.addEventListener('click', function () {
- const cropRect = region
- const canvas = document.createElement('canvas')
- const context = canvas.getContext('2d')
- const imageObj = new Image()
- canvas.width = cropRect.width
- canvas.height = cropRect.height
- imageObj.src = url
- imageObj.onload = function () {
- context.drawImage(imageObj, cropRect.x, cropRect.y, cropRect.width, cropRect.height, 0, 0, cropRect.width, cropRect.height)
- let ImgUrl = canvas.toDataURL()
- v.image.src = ImgUrl
-
- switch (BACKGROUND_TYPE) {
- case 'blurred':
- injectCSS(`
- .blurry-bg {
- background-image: url("${ImgUrl}");
- }`)
- break
- case 'light':
- break
- case 'dark':
- break
- default:
- break
- }
-
- setTimeout(function () {
- window.dispatchEvent(new Event('resize'))
- IS_CROP_OPEN = false
- winbox.close()
- }, 100)
- }
-
- // image.addEventListener('load', () => {
-
- // console.log(image)
- // context.drawImage(
- // //croppr.imageEl,
- // v.element,
- // cropRect.x,
- // cropRect.y,
- // cropRect.width,
- // cropRect.height,
- // 0,
- // 0,
- // canvas.width,
- // canvas.height,
- // );
- // });
-
- //
-
- //v.image.src = ImgUrl;
-
- // switch (BACKGROUND_TYPE) {
- // case 'blurred':
- // injectCSS(`
- // .blurry-bg {
- // background-image: url("${ImgUrl}");
- // }`);
- // break;
- // case 'light':
- // break;
- // case 'dark':
- // break;
- // default:
- // break;
- // }
-
- // setTimeout(function () {
- // v.zoom(0.5);
- // window.dispatchEvent(new Event('resize'));
- // }, 100);
-
- // //showNotification("Image cropped successfully", '#ffffff', '#000000', settings)
- // IS_CROP_OPEN = false;
- // winbox.close();
- })
- }, 100)
-}
-
-// canvas function
-function useCanvas(el, image, callback) {
- el.width = image.width // img width
- el.height = image.height // img height
- // draw image in canvas tag
- el.getContext('2d').drawImage(image, 0, 0, image.width, image.height)
- return callback()
-}
-
-function componentToHex(c) {
- let hex = c.toString(16)
- return hex.length == 1 ? '0' + hex : hex
-}
-function rgbToHex(r, g, b) {
- return '#' + componentToHex(r) + componentToHex(g) + componentToHex(b)
-}
-
-function findPos(obj) {
- let curleft = 0,
- curtop = 0
- if (obj.offsetParent) {
- do {
- curleft += obj.offsetLeft
- curtop += obj.offsetTop
- } while ((obj = obj.offsetParent))
- return { x: curleft, y: curtop }
- }
- return undefined
-}
-
-function resetColorPicker(winboxPicker, v) {
- //console.log(e);
-}
-
-const handleImageClickOnPicker = (e, v, canvas, pickr, x, y, settings) => {
- if (e.offsetX) {
- x = e.offsetX
- y = e.offsetY
- }
-
- console.log(settings)
-
- useCanvas(canvas, v.image, () => {
- // get image data
- let p = canvas.getContext('2d').getImageData(x, y, 1, 1).data
- // show info
- pickr.setColor(rgbToHex(p[0], p[1], p[2]))
- copyToClipboard(rgbToHex(p[0], p[1], p[2]))
- showNotification(`${rgbToHex(p[0], p[1], p[2]).toUpperCase()} copied to clipboard`, getColorByBgColor(rgbToHex(p[0], p[1], p[2])), rgbToHex(p[0], p[1], p[2]), settings)
- })
-}
-
-const handleMouseMoveOnPicker = (e, v, canvas, pickr, x, y) => {
- if (e.offsetX) {
- x = e.offsetX
- y = e.offsetY
- }
- useCanvas(canvas, v.image, function () {
- // get image data
- let p = canvas.getContext('2d').getImageData(x, y, 1, 1).data
- pickr.setColor(rgbToHex(p[0], p[1], p[2]))
- })
-}
-
-/**
- * Get color (black/white) depending on bgColor so it would be clearly seen.
- * @param {string} bgColor
- * @returns {string}
- */
-function getColorByBgColor(bgColor) {
- if (!bgColor) {
- return ''
- }
- return parseInt(bgColor.replace('#', ''), 16) > 0xffffff / 2 ? '#000' : '#fff'
-}
-
-/**
- * Copy string to clipboard
- * @param {string} str - string to copy
- */
-function copyToClipboard(textToCopy) {
- // navigator clipboard api needs a secure context (https)
- if (navigator.clipboard && window.isSecureContext) {
- // navigator clipboard api method'
- return navigator.clipboard.writeText(textToCopy)
- } else {
- // text area method
- let textArea = document.createElement('textarea')
- textArea.value = textToCopy
- // make the textarea out of viewport
- textArea.style.position = 'fixed'
- textArea.style.left = '-999999px'
- textArea.style.top = '-999999px'
- document.body.appendChild(textArea)
- textArea.focus()
- textArea.select()
- return new Promise((res, rej) => {
- // here the magic happens
- document.execCommand('copy') ? res() : rej()
- textArea.remove()
- })
- }
-}
-
-function printImage(image) {
- let strb64 = getBase64Image(image)
- printJS(strb64, 'image')
-}
-
-/**
- * Convert image to base64
- * @param {*} img Image element
- * @returns
- */
-function getBase64Image(img) {
- let canvas = document.createElement('canvas')
- canvas.width = img.naturalWidth
- canvas.height = img.naturalHeight
- let ctx = canvas.getContext('2d')
- ctx.drawImage(img, 0, 0)
- return canvas.toDataURL()
-}
-
-function changeTheme(imgsrc, settings) {
- let lightTheme = `background-image: url("data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-sun'%3E%3Ccircle cx='12' cy='12' r='5'%3E%3C/circle%3E%3Cline x1='12' y1='1' x2='12' y2='3'%3E%3C/line%3E%3Cline x1='12' y1='21' x2='12' y2='23'%3E%3C/line%3E%3Cline x1='4.22' y1='4.22' x2='5.64' y2='5.64'%3E%3C/line%3E%3Cline x1='18.36' y1='18.36' x2='19.78' y2='19.78'%3E%3C/line%3E%3Cline x1='1' y1='12' x2='3' y2='12'%3E%3C/line%3E%3Cline x1='21' y1='12' x2='23' y2='12'%3E%3C/line%3E%3Cline x1='4.22' y1='19.78' x2='5.64' y2='18.36'%3E%3C/line%3E%3Cline x1='18.36' y1='5.64' x2='19.78' y2='4.22'%3E%3C/line%3E%3C/svg%3E");`
- let darkTheme = `background-image: url("data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-moon'%3E%3Cpath d='M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z'%3E%3C/path%3E%3C/svg%3E");`
- let blurTheme = `background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-droplet'%3E%3Cpath d='M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z'%3E%3C/path%3E%3C/svg%3E"); `
-
- switch (BACKGROUND_TYPE) {
- case 'blurred':
- showNotification('☀️ Light Background', '#000000', '#ffffff', settings)
- injectCSS(`
- .viewer-theme {
- ${darkTheme}
- }
- .blurry-bg {
- transition: all 0.5s ease;
- background-image: none;
- background-color: #ffffff;
- filter: blur(0px);
- -webkit-filter: blur(0px);
- height: 100%;
- background-position: center;
- background-repeat: no-repeat;
- background-size: cover;
- width: 100vw;
- height: 100vh;
- transform: scale(1.3);
- }
- .blurry-bg:before {
- opacity: 0;
- }
-
- `)
- BACKGROUND_TYPE = 'light'
- break
- case 'light':
- showNotification('🌑 Dark Background', '#ffffff', '#000000', settings)
- injectCSS(`
- .viewer-theme {
- ${blurTheme}
- }
- .blurry-bg {
- transition: all 0.5s ease;
- background-image: none;
- background-color: #0e1217;
- filter: blur(0px);
- -webkit-filter: blur(0px);
- height: 100%;
- background-position: center;
- background-repeat: no-repeat;
- background-size: cover;
- width: 100vw;
- height: 100vh;
- transform: scale(1.3);
- opacity: 0;
- }
- .blurry-bg:before {
- opacity: 0;
- }
- `)
- BACKGROUND_TYPE = 'dark'
- break
- case 'dark':
- // change to blurred
- showNotification('💧 Blurred Background', '#ffffff', '#404040', settings)
- injectCSS(`
- .viewer-theme {
- ${lightTheme}
- }
- .blurry-bg {
- transition: none;
- background-image: url("${imgsrc}");
- background-color: none;
- filter: blur(15px);
- -webkit-filter: blur(15px);
- height: 100%;
- background-position: center;
- background-repeat: no-repeat;
- background-size: cover;
- width: 100vw;
- height: 100vh;
- transform: scale(1.3);
- opacity: 1;
- }
- .blurry-bg:before {
- opacity: 0.5;
- }`)
- BACKGROUND_TYPE = 'blurred'
- break
- }
-}
-
-function showNotification(text, textColor, bgColor, settings) {
- Toastify({
- text: `${text}`,
- duration: 3000,
- newWindow: true,
- close: false,
- gravity: settings.settings.notification_gravity, // `top` or `bottom`
- position: settings.settings.notification_position, // `left`, `center` or `right`
- stopOnFocus: true, // Prevents dismissing of toast on hover
- style: {
- color: textColor,
- background: bgColor
- }
- }).showToast()
-}
-
-// hardcoded toast position for the shortcut.html save button -- fix if possible
-function showNotificationShortcuts(text, textColor, bgColor) {
-
- Toastify({
- text: `${text}`,
- duration: 3000,
- newWindow: true,
- close: false,
- gravity: 'top', // `top` or `bottom`
- position: 'right', // `left`, `center` or `right`
- stopOnFocus: true, // Prevents dismissing of toast on hover
- style: {
- color: textColor,
- background: bgColor,
- }
- }).showToast();
-}
-
-
-function jsonViewer(json, collapsible = false) {
- let TEMPLATES = {
- item: '',
- itemCollapsible: '',
- itemCollapsibleOpen: ''
- }
-
- function createItem(key, value, type) {
- let element = TEMPLATES.item.replace('%KEY%', key)
-
- if (type == 'string') {
- element = element.replace('%VALUE%', '"' + value + '"')
- } else {
- element = element.replace('%VALUE%', value)
- }
-
- element = element.replace('%TYPE%', type)
-
- return element
- }
-
- function createCollapsibleItem(key, value, type, children) {
- let tpl = 'itemCollapsible'
-
- if (collapsible) {
- tpl = 'itemCollapsibleOpen'
- }
-
- let element = TEMPLATES[tpl].replace('%KEY%', key)
-
- element = element.replace('%VALUE%', type)
- element = element.replace('%TYPE%', type)
- element = element.replace('%CHILDREN%', children)
-
- return element
- }
-
- function handleChildren(key, value, type) {
- let html = ''
-
- for (let item in value) {
- let _key = item,
- _val = value[item]
-
- html += handleItem(_key, _val)
- }
-
- return createCollapsibleItem(key, value, type, html)
- }
-
- function handleItem(key, value) {
- let type = typeof value
-
- if (typeof value === 'object') {
- return handleChildren(key, value, type)
- }
-
- return createItem(key, value, type)
- }
-
- function parseObject(obj) {
- let _result = ''
-
- for (let item in obj) {
- let key = item,
- value = obj[item]
-
- _result += handleItem(key, value)
- }
-
- _result += '
'
-
- return _result
- }
-
- return parseObject(json)
-}
-
-// listen to messages from iframe
-window.addEventListener('message', function (message) {
- if (message.data.type == "settings") {
- let user_settings = message.data.settings
- // save using chrome.storage
- chrome.storage.sync.set({
- settings: user_settings
- }, function () {
- // Notify that we saved.
- showNotification('💾 Settings saved successfully', '#ffffff', '#000000', message.data);
- setTimeout(() => {
- // reload window after saving
- window.location.reload();
- }, 1000)
- });
- };
-
- if (message.data.type == "shortcutHotkeys") {
- let user_shortcutHotkeys = message.data.shortcutHotkeys
- // save using chrome.storage
- chrome.storage.sync.set({
- shortcutHotkeys: user_shortcutHotkeys,
- }, function () {
- // Notify that we saved.
- showNotificationShortcuts('💾 Shortcuts saved successfully', '#ffffff', '#000000', message.data);
- setTimeout(() => {
- // reload window after saving
- window.location.reload();
- }, 1000)
- });
- };
-});
-
-
-
+// run when scripts and styles are loaded
+chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
+ if (request.type == 'injected') {
+ chrome.storage.sync.get('settings', function (settings) {
+ try {
+ if (settings.settings) {
+ init(settings)
+ }
+ } catch (e) {
+ console.error('error while loading settings: ', e)
+ }
+ })
+ }
+})
+
+let IS_PICKER_OPEN = false
+let IS_DETAILS_OPEN = false
+let IS_HELP_OPEN = false
+let IS_CROP_OPEN = false
+
+let viewer
+let isLocalFile = window.location.href.match(/(file:\/\/)/) ? true : false;
+let BACKGROUND_TYPE = 'blurred'
+let UPLOAD_SITE = 'imgbb'
+let ImgCanvas
+let isFlippedHorizontally = false
+let isFlippedVertically = false
+let IMGBB_TOKEN = '8be35a61597b285f9c95669fdc565b00'
+let IMGUR_TOKEN = '405d491c9e67e9f'
+let isKeypressEnabled = false
+let WINBOX_CLASSES = ['no-scrollbar', 'no-max', 'no-min', 'no-full', 'no-resize', 'no-animation']
+let ocrLangList = {
+ Afrikaans: 'afr',
+ Albanian: 'sqi',
+ Amharic: 'amh',
+ Arabic: 'ara',
+ Armenian: 'hye',
+ Azerbaijani: 'aze',
+ Basque: 'eus',
+ Belarusian: 'bel',
+ Bengali: 'ben',
+ Bosnian: 'bos',
+ Bulgarian: 'bul',
+ Burmese: 'mya',
+ Catalan: 'cat',
+ Cebuano: 'ceb',
+ 'Chinese Simplified': 'chi_sim',
+ 'Chinese Simplified (vertical)': 'chi_sim_vert',
+ 'Chinese Traditional': 'chi_tra',
+ 'Chinese Traditional (vertical)': 'chi_tra_vert',
+ Corsican: 'cos',
+ Croatian: 'hrv',
+ Czech: 'ces',
+ Danish: 'dan',
+ Dutch: 'nld',
+ English: 'eng',
+ Esperanto: 'epo',
+ Estonian: 'est',
+ Filipino: 'fil',
+ Finnish: 'fin',
+ French: 'fra',
+ Frisian: 'fry',
+ Galician: 'glg',
+ Georgian: 'kat',
+ German: 'deu',
+ Greek: 'ell',
+ Gujarati: 'guj',
+ Haitian: 'hat',
+ Hebrew: 'heb',
+ Hindi: 'hin',
+ Hungarian: 'hun',
+ Icelandic: 'isl',
+ Indonesian: 'ind',
+ Irish: 'gle',
+ Italian: 'ita',
+ Japanese: 'jpn',
+ 'Japanese (vertical)': 'jpn_vert',
+ Javanese: 'jav',
+ Kannada: 'kan',
+ Kazakh: 'kaz',
+ Khmer: 'khm',
+ Korean: 'kor',
+ 'Korean (vertical)': 'kor_vert',
+ Kurdish: 'kmr',
+ Lao: 'lao',
+ Latin: 'lat',
+ Latvian: 'lav',
+ Lithuanian: 'lit',
+ Luxembourgish: 'ltz',
+ Macedonian: 'mkd',
+ Malay: 'msa',
+ Malayalam: 'mal',
+ Maltese: 'mlt',
+ Maori: 'mri',
+ Marathi: 'mar',
+ Mongolian: 'mon',
+ Nepali: 'nep',
+ Norwegian: 'nor',
+ Persian: 'fas',
+ Polish: 'pol',
+ Portuguese: 'por',
+ Romanian: 'ron',
+ Russian: 'rus',
+ 'Scottish Gaelic': 'gla',
+ Serbian: 'srp',
+ Sindhi: 'snd',
+ Sinhala: 'sin',
+ Slovak: 'slk',
+ Slovenian: 'slv',
+ Spanish: 'spa',
+ Sundanese: 'sun',
+ Swahili: 'swa',
+ Swedish: 'swe',
+ Tajik: 'tgk',
+ Tamil: 'tam',
+ Telugu: 'tel',
+ Thai: 'tha',
+ Turkish: 'tur',
+ Ukrainian: 'ukr',
+ Urdu: 'urd',
+ Uzbek: 'uzb',
+ Vietnamese: 'vie',
+ Welsh: 'cym',
+ Yiddish: 'yid',
+ Yoruba: 'yor'
+}
+let tippyData = [
+ {
+ type: 'zoom-in',
+ text: 'Zoom In'
+ },
+ {
+ type: 'zoom-out',
+ text: 'Zoom Out'
+ },
+ {
+ type: 'one-to-one',
+ text: '1:1'
+ },
+ {
+ type: 'reset',
+ text: 'Reset'
+ },
+ {
+ type: 'fit-to-screen',
+ text: 'Fit to Screen'
+ },
+ {
+ type: 'rotate-left',
+ text: 'Rotate Left'
+ },
+ {
+ type: 'rotate-right',
+ text: 'Rotate Right'
+ },
+ {
+ type: 'flip-horizontal',
+ text: 'Flip Horizontal'
+ },
+ {
+ type: 'flip-vertical',
+ text: 'Flip Vertical'
+ },
+ {
+ type: 'crop',
+ text: 'Crop Image'
+ },
+ {
+ type: 'download',
+ text: 'Download'
+ },
+ {
+ type: 'play',
+ text: 'Fullscreen'
+ },
+ {
+ type: 'details',
+ text: 'Details'
+ },
+ {
+ type: 'colorpicker',
+ text: 'Color Picker'
+ },
+ {
+ type: 'paint',
+ text: 'Photo Editor'
+ },
+ {
+ type: 'print',
+ text: 'Print image'
+ },
+ {
+ type: 'help',
+ text: 'Help'
+ },
+ {
+ type: 'theme',
+ text: 'Toggle Theme'
+ },
+ {
+ type: 'exit',
+ text: 'Turn Off'
+ },
+ {
+ type: 'upload',
+ text: 'Upload Image'
+ },
+ {
+ type: 'ocr',
+ text: 'Extract Text'
+ },
+ {
+ type: 'photopea',
+ text: 'Edit in Photopea'
+ },
+ {
+ type: 'tineye',
+ text: 'Reverse Image Search'
+ },
+ {
+ type: 'about',
+ text: 'About'
+ },
+ {
+ type: 'qr',
+ text: 'QR Code Scanner'
+ },
+ {
+ type: 'settings',
+ text: 'Settings'
+ }
+]
+
+// ~~~ Custom Shortcut Hotkeys Section ~~~ \\
+chrome.storage.sync.get("shortcutHotkeys", (shortcutHotkeys) => {
+ const sc_sc = shortcutHotkeys.shortcutHotkeys;
+
+ document.addEventListener("keydown", function (e) {
+ let activeModifier;
+ if (e.ctrlKey) {activeModifier = "mod";} else if (e.shiftKey) {activeModifier = "shift";} else if (e.altKey) {activeModifier = "alt";};
+
+ if (!isKeypressEnabled) {
+ // if shortcut toggle = on { set custom hotkey; activate shortcut}
+ if (sc_sc.zoomInToggle === true) {
+ const hotkeyMod = sc_sc.zoom_in_mod;
+ const hotkeyKey = sc_sc.zoom_in_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ // uses the custom hotkey to execute the selected shortcut
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-zoom-in')[0].click();
+ // prevent the default shortcut
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.zoomOutToggle === true) {
+ const hotkeyMod = sc_sc.zoom_out_mod;
+ const hotkeyKey = sc_sc.zoom_out_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-zoom-out')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.oneToOneToggle === true) {
+ const hotkeyMod = sc_sc.one_to_one_mod
+ const hotkeyKey = sc_sc.one_to_one_key
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-one-to-one')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.resetToggle === true) {
+ const hotkeyMod = sc_sc.reset_mod;
+ const hotkeyKey = sc_sc.reset_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName("viewer-reset")[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.fitToScreenToggle === true) {
+ const hotkeyMod = sc_sc.fit_to_screen_mod;
+ const hotkeyKey = sc_sc.fit_to_screen_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-fit-to-screen')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.fullscreenToggle === true) {
+ const hotkeyMod = sc_sc.fullscreen_mod;
+ const hotkeyKey = sc_sc.fullscreen_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-play')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.rotateLeftToggle === true) {
+ const hotkeyMod = sc_sc.rotate_left_mod;
+ const hotkeyKey = sc_sc.rotate_left_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-rotate-left')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.rotateRightToggle === true) {
+ const hotkeyMod = sc_sc.rotate_right_mod;
+ const hotkeyKey = sc_sc.rotate_right_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-rotate-right')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.flipHorizontalToggle === true) {
+ const hotkeyMod = sc_sc.flip_horizontal_mod;
+ const hotkeyKey = sc_sc.flip_horizontal_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-flip-horizontal')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.flipVerticalToggle === true) {
+ const hotkeyMod = sc_sc.flip_vertical_mod;
+ const hotkeyKey = sc_sc.flip_vertical_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-flip-vertical')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.cropImageToggle === true) {
+ const hotkeyMod = sc_sc.crop_mod;
+ const hotkeyKey = sc_sc.crop_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-crop')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.photoEditorToggle === true) {
+ const hotkeyMod = sc_sc.photo_editor_mod;
+ const hotkeyKey = sc_sc.photo_editor_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-paint')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.downloadToggle === true) {
+ const hotkeyMod = sc_sc.download_mod;
+ const hotkeyKey = sc_sc.download_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-download')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.uploadImageToggle === true) {
+ const hotkeyMod = sc_sc.upload_mod;
+ const hotkeyKey = sc_sc.upload_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-upload')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.colorPickerToggle === true) {
+ const hotkeyMod = sc_sc.color_picker_mod;
+ const hotkeyKey = sc_sc.color_picker_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-colorpicker')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.detailsToggle === true) {
+ const hotkeyMod = sc_sc.details_mod;
+ const hotkeyKey = sc_sc.details_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-details')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.themeToggle === true) {
+ const hotkeyMod = sc_sc.theme_mod;
+ const hotkeyKey = sc_sc.theme_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-theme')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.printImageToggle === true) {
+ const hotkeyMod = sc_sc.print_mod;
+ const hotkeyKey = sc_sc.print_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-print')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.extractTextToggle === true) {
+ const hotkeyMod = sc_sc.extract_text_mod;
+ const hotkeyKey = sc_sc.extract_text_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-ocr')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.photopeaToggle === true) {
+ const hotkeyMod = sc_sc.photopea_mod;
+ const hotkeyKey = sc_sc.photopea_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-photopea')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.reverseSearchToggle === true) {
+ const hotkeyMod = sc_sc.reverse_search_mod;
+ const hotkeyKey = sc_sc.reverse_search_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-tineye')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.helpToggle === true) {
+ const hotkeyMod = sc_sc.help_mod;
+ const hotkeyKey = sc_sc.help_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-help')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ if (sc_sc.turnOffToggle === true) {
+ const hotkeyMod = sc_sc.turn_off_mod;
+ const hotkeyKey = sc_sc.turn_off_key;
+ const customHotkey = hotkeyMod + "+" + hotkeyKey;
+
+ Mousetrap.bind(customHotkey, (e) => {
+ document.getElementsByClassName('viewer-exit')[0].click();
+ e.preventDefault();
+ });
+ }
+
+ }
+ });
+});
+
+
+
+
+ // ~~~ Initializes the Extension ~~~ \\
+function init(settings) {
+ BACKGROUND_TYPE = settings.settings.default_theme
+ UPLOAD_SITE = settings.settings.upload_site
+
+ // checks the zoom setting - if it's nulled, then the default is set to 0.1 (10%)
+ settings.settings.zoom_ratio == null ? (settings.settings.zoom_ratio = 0.1) : (zoomSetting = settings.settings.zoom_ratio)
+ zoomSetting = settings.settings.zoom_ratio
+
+ let imgElement = document.getElementsByTagName('img')[0] // get img element
+ // if img element is found
+ if (imgElement) {
+ let blurryDiv = document.createElement('div') // create blurry div
+ blurryDiv.setAttribute('class', 'blurry-bg') // add class to blurry div
+ imgElement.parentNode.insertBefore(blurryDiv, imgElement) // add before img element
+
+ // init Viewer
+ viewer = new Viewer(imgElement, {
+ inline: false,
+ loading: false,
+ interval: 0,
+ zoomable: true,
+ transition: true,
+ navbar: false,
+ title: false,
+ keyboard: false,
+ backdrop: false, // prevent exit when click backdrop
+ zoomRatio: zoomSetting,
+ toolbar: {
+ next: false,
+ prev: false,
+ zoomIn: settings.settings.zoomIn && {
+ show: 1,
+ size: 'large'
+ },
+ zoomOut: settings.settings.zoomOut && {
+ show: 1,
+ size: 'large'
+ },
+ reset: settings.settings.reset && {
+ show: 1,
+ size: 'large',
+ click: function () {
+ viewer.image.src = window.location.href
+ viewer.reset()
+ setTimeout(() => {
+ if (settings.settings.toolbar_position === 'top') {
+ viewer.move(0, 50)
+ }
+ }, 100)
+ window.dispatchEvent(new Event('resize'))
+ }
+ },
+ oneToOne: settings.settings.oneToOne && {
+ show: 1,
+ size: 'large'
+ },
+ fitToScreen: settings.settings.fitToScreen && {
+ show: 1,
+ size: 'large',
+ click: function () {
+ // Calculates a Zoom Ratio, based off of the Max & Default height/width
+ let heightRatio = window.innerHeight / imgElement.naturalHeight;
+ let widthRatio = window.innerWidth / imgElement.naturalWidth
+
+ // Zooms to the Max Height & Centers the Image : if Zoomed Width > Max Width, scale to the Max Width instead
+ if (imgElement.naturalWidth*heightRatio > window.innerWidth) {
+ viewer.zoomTo(widthRatio, true);
+ viewer.moveTo(0, (window.innerHeight - (imgElement.naturalHeight * widthRatio))/2);
+ } else {
+ viewer.zoomTo(heightRatio, true);
+ viewer.moveTo((window.innerWidth - (imgElement.naturalWidth * heightRatio))/2, 0);
+ }
+ }
+ },
+ play: settings.settings.play && {
+ show: 1,
+ size: 'large',
+ click: function () {
+ viewer.image
+ .requestFullscreen()
+ .then(function () {
+ // console.log('requestFullscreen success');
+ })
+ .catch(function (error) {
+ console.error(error)
+ })
+ }
+ },
+ rotateLeft: settings.settings.rotateLeft && {
+ show: 1,
+ size: 'large'
+ },
+ rotateRight: settings.settings.rotateRight && {
+ show: 1,
+ size: 'large'
+ },
+ flipHorizontal: settings.settings.flipHorizontal && {
+ show: 1,
+ size: 'large'
+ },
+ flipVertical: settings.settings.flipVertical && {
+ show: 1,
+ size: 'large'
+ },
+ crop: settings.settings.crop && {
+ show: 1,
+ size: 'large',
+ click: function () {
+ if (!IS_CROP_OPEN) {
+ IS_CROP_OPEN = true
+ // reset viewer
+ //viewer.reset();
+ let reset = viewer.reset()
+ setTimeout(() => {
+ if (settings.settings.toolbar_position === 'top') {
+ viewer.move(0, 50)
+ }
+ }, 100)
+ if (reset) {
+ crop(viewer, viewer.image.src, viewer.image.width, viewer.image.height)
+ }
+ }
+ }
+ },
+ paint: settings.settings.paint && {
+ show: isLocalFile ? 0 : 1,
+ size: 'large',
+ click: function () {
+ isKeypressEnabled = true
+ // create new winbox
+ let winboxPaint = new WinBox('Photo Editor', {
+ class: ['no-scrollbar', 'no-min', 'no-animation'],
+ index: 9999,
+ x: 'center',
+ y: 'center',
+ width: '90%',
+ height: '90%',
+ background: 'rgba(0,0,0,0.9)',
+ html: ``
+ })
+
+ winboxPaint.show()
+
+ const config = {
+ theme: {
+ palette: {
+ 'txt-primary': '#ffffff',
+ 'txt-primary-invert': '#ffffff',
+ // 'txt-secondary': '#ffffff',
+ // 'txt-secondary-invert': '#ffffff',
+ // 'txt-placeholder': '#ffffff',
+ 'accent-primary': '#1E262C',
+ 'accent-primary-hover': '#000000',
+ 'accent-primary-active': '#000000',
+ // 'accent-primary-disabled': '#ffffff',
+ 'bg-primary': '#00000000' // canvas bg
+ //'bg-primary-hover': '#000000',
+ //'bg-primary-active': '#000000',
+ //'bg-primary-0-5-opacity': '#ffffff',
+ //'bg-secondary': '#ffffff',
+ //'icons-primary': '#ffffff',
+ //'icons-primary-opacity-0-6': '#ffffff',
+ //'icons-secondary': '#ffffff',
+ // 'btn-primary-text': '#ffffff',
+ // 'btn-disabled-text': '#ffffff',
+ // 'link-primary': '#ffffff',
+ // 'link-hover': '#ffffff',
+ // 'link-active': '#ffffff',
+ // 'borders-primary': '#ffffff',
+ // 'borders-secondary': '#ffffff',
+ // 'borders-strong': '#ffffff',
+ // 'borders-invert': '#ffffff',
+ // 'border-active-bottom': '#ffffff',
+ // 'active-secondary': '#ffffff',
+ // 'active-secondary-hover': '#ffffff',
+ // 'active-secondary-active': '#ffffff',
+ // 'tag': '#ffffff',
+ // 'error': '#ffffff',
+ // 'success': '#ffffff',
+ // 'warning': '#ffffff',
+ // 'info': '#ffffff',
+ // 'light-shadow': '#ffffff',
+ }
+ },
+ onBeforeSave: function (imageFileInfo) {
+ // prevent default behavior
+ return false
+ },
+ onSave: function (imageData, imageDesignState) {
+ console.log('~ imageDesignState', imageDesignState)
+ console.log('~ imageData', imageData)
+ let newImgBase64 = imageData.imageBase64
+ let imgElements = document.getElementsByTagName('img')
+ for (let elem of imgElements) {
+ elem.src = newImgBase64
+ }
+ // trigger resize event in setTimeout
+ setTimeout(function () {
+ window.dispatchEvent(new Event('resize'))
+ }, 100)
+ showNotification('💾 Image saved successfully', '#ffffff', '#000000', settings)
+ setTimeout(() => {
+ if (settings.settings.toolbar_position === 'top') {
+ viewer.move(0, 50)
+ }
+ }, 100)
+ winboxPaint.close()
+ },
+ moreSaveOptions: [
+ {
+ label: 'Save as new file',
+ onClick: (triggerSaveModal, triggerSave) =>
+ triggerSaveModal((...args) => {
+ let a = document.createElement('a')
+ a.href = args[0].imageBase64
+ a.download = args[0].fullName
+ a.click()
+
+ showNotification('💾 Image downloaded successfully', '#ffffff', '#000000', settings)
+ })
+ }
+ ],
+ source: viewer.image.src,
+ //onSave: (editedImageObject, designState) => console.log('saved', editedImageObject, designState),
+ annotationsCommon: {
+ fill: '#ff0000'
+ },
+ Text: { text: 'Your Text Here...' },
+ translations: {
+ profile: 'Profile',
+ coverPhoto: 'Cover photo',
+ facebook: 'Facebook',
+ socialMedia: 'Social Media',
+ fbProfileSize: '180x180px',
+ fbCoverPhotoSize: '820x312px'
+ },
+ Crop: {
+ presetsItems: [
+ {
+ titleKey: 'classicTv',
+ descriptionKey: '4:3',
+ ratio: 4 / 3
+ // icon: CropClassicTv, // optional, CropClassicTv is a React Function component. Possible (React Function component, string or HTML Element)
+ },
+ {
+ titleKey: 'cinemascope',
+ descriptionKey: '21:9',
+ ratio: 21 / 9
+ // icon: CropCinemaScope, // optional, CropCinemaScope is a React Function component. Possible (React Function component, string or HTML Element)
+ }
+ ],
+ presetsFolders: [
+ {
+ titleKey: 'socialMedia', // will be translated into Social Media as backend contains this translation key
+ // icon: Social, // optional, Social is a React Function component. Possible (React Function component, string or HTML Element)
+ groups: [
+ {
+ titleKey: 'facebook',
+ items: [
+ {
+ titleKey: 'profile',
+ width: 180,
+ height: 180,
+ descriptionKey: 'fbProfileSize'
+ },
+ {
+ titleKey: 'coverPhoto',
+ width: 820,
+ height: 312,
+ descriptionKey: 'fbCoverPhotoSize'
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ tabsIds: [window.FilerobotImageEditor.TABS.ADJUST, window.FilerobotImageEditor.TABS.ANNOTATE, window.FilerobotImageEditor.TABS.WATERMARK, window.FilerobotImageEditor.TABS.FILTERS, window.FilerobotImageEditor.TABS.FINETUNE, window.FilerobotImageEditor.TABS.RESIZE], // or ['Adjust', 'Annotate', 'Watermark']
+ defaultTabId: window.FilerobotImageEditor.TABS.ANNOTATE, // or 'Annotate'
+ defaultToolId: window.FilerobotImageEditor.TOOLS.TEXT // or 'Text'
+ }
+
+ console.log(window.FilerobotImageEditor.TABS)
+
+ // Assuming we have a div with id="editor_container"
+ const filerobotImageEditor = new FilerobotImageEditor(document.querySelector('#paint-wrapper'), config)
+
+ filerobotImageEditor.render({
+ onClose: closingReason => {
+ console.log('Closing reason', closingReason)
+ filerobotImageEditor.terminate()
+ }
+ })
+
+ // window.p = Painterro({
+ // hideByEsc: true,
+ // saveByEnter: true,
+ // hiddenTools: [
+ // 'open', 'close', 'resize', 'eraser'
+ // ],
+ // id: 'paint-wrapper',
+ // availableLineWidths: [1, 2, 4, 8, 16, 64],
+ // availableEraserWidths: [1, 2, 4, 8, 16, 64],
+ // availableFontSizes: [1, 2, 4, 8, 16, 64],
+ // availableArrowLengths: [10, 20, 30, 40, 50, 60],
+ // defaultTool: 'brush',
+ // saveHandler: (image, done) => {
+
+ // let newImgBase64 = image.asDataURL();
+
+ // let imgElements = document.getElementsByTagName('img');
+ // // loop through all img elements
+ // // for (let i = 0; i < imgElements.length; i++) {
+ // // // replace image with cropped image
+ // // imgElements[i].src = newImgBase64;
+ // // }
+
+ // for (let elem of imgElements) {
+ // elem.src = newImgBase64;
+ // }
+
+ // // trigger resize event in setTimeout
+ // setTimeout(function () {
+ // window.dispatchEvent(new Event('resize'));
+ // }, 100);
+
+ // showNotification('💾 Image saved successfully', '#ffffff', '#000000', settings);
+ // setTimeout(() => {
+ // if (settings.settings.toolbar_position === 'top') {
+ // viewer.move(0, 50);
+ // }
+ // }, 100);
+
+ // winboxPaint.close();
+ // done(true);
+ // }
+ // }).show(viewer.image.src);
+ }
+ },
+ download: settings.settings.download && {
+ show: isLocalFile ? 0 : 1,
+ size: 'large',
+ click: function () {
+ download(viewer.image)
+ }
+ },
+ upload: settings.settings.upload && {
+ show: isLocalFile ? 0 : 1,
+ size: 'large',
+ click: function () {
+ let uriString = getBase64Image(viewer.image)
+
+ // get base64 part from string
+ let base64 = uriString.split(',')[1]
+
+ // create html element with text
+ let x = document.createElement('div')
+ // set flex
+ x.style.display = 'flex'
+ // set element inner html
+ x.innerHTML = ` Uploading image... Please wait`
+
+ Toastify({
+ node: x,
+ duration: 999999,
+ newWindow: true,
+ close: false,
+ gravity: settings.settings.notification_gravity, // `top` or `bottom`
+ position: settings.settings.notification_position, // `left`, `center` or `right`
+ stopOnFocus: true, // Prevents dismissing of toast on hover
+ style: {
+ color: '#ffffff',
+ background: '#000000'
+ }
+ //onClick: function () { } // Callback after click
+ }).showToast()
+
+ // upload image to either imgbb or imgur, depending on the current setting
+ switch (UPLOAD_SITE) {
+ // upload to imgbb
+ case 'imgbb':
+ let formdata = new FormData()
+ formdata.append('image', base64)
+
+ let requestOptionsIMGBB = {
+ method: 'POST',
+ body: formdata,
+ redirect: 'follow'
+ }
+
+ fetch(`https://api.imgbb.com/1/upload?expiration=600&key=${IMGBB_TOKEN}`, requestOptionsIMGBB)
+ .then(res => res.json())
+ .then(res => {
+ // remove toast
+ let toastifyElems = document.querySelectorAll('.toastify')
+ toastifyElems.forEach(element => {
+ element.remove()
+ })
+
+ copyToClipboard(res.data.image.url)
+ showNotification('✔️ Image uploaded successfully', '#ffffff', '#000000', settings)
+ showNotification(`📋 URL copied to clipboard`, '#ffffff', '#000000', settings)
+ })
+ break
+ // upload to imgur
+ case 'imgur':
+ let requestOptionsIMGUR = {
+ method: 'POST',
+ headers: { 'Authorization': `Client-ID ${IMGUR_TOKEN}` },
+ body: base64
+ }
+
+ fetch('https://api.imgur.com/3/image', requestOptionsIMGUR)
+ .then(res => res.json())
+ .then((res) => {
+ // remove toast
+ let toastifyElems = document.querySelectorAll('.toastify');
+ toastifyElems.forEach(element => {
+ element.remove()
+ });
+
+ copyToClipboard(res.data.link);
+ showNotification('✔️ Image uploaded successfully', '#ffffff', '#000000', settings)
+ showNotification(`📋 URL copied to clipboard`, '#ffffff', '#000000', settings)
+ });
+ break
+ }
+ }
+ },
+ colorpicker: settings.settings.colorpicker && {
+ show: isLocalFile ? 0 : 1,
+ size: 'large',
+ click: async function () {
+ if (!IS_PICKER_OPEN) {
+ IS_PICKER_OPEN = true
+
+ // change cursor to picker
+ viewer.image.style.cursor = 'crosshair'
+
+ let colorPickerBox = new WinBox('Color Preview', {
+ class: WINBOX_CLASSES,
+ background: 'rgba(0,0,0,0.9)',
+ index: 9999,
+ width: '250px',
+ height: '250px',
+ y: 'bottom',
+ x: '10px',
+ html: `
+ `,
+ onclose: function () {
+ IS_PICKER_OPEN = false
+ // change cursor back to default
+ viewer.image.style.cursor = 'default'
+ viewer.image.click() // trigger a click to remove the event listener
+ }
+ })
+
+ // init color picker
+ const pickr = Pickr.create({
+ el: '.color-picker',
+ inline: true,
+ showAlways: true,
+ theme: 'classic', // or 'monolith', or 'nano'
+ useAsButton: false,
+ autoReposition: true,
+ appClass: 'color-picker-app',
+ components: {
+ // Main components
+ preview: true,
+ opacity: false,
+ hue: true,
+
+ // Input / output Options
+ interaction: {
+ hex: true,
+ rgba: true,
+ hsla: true,
+ hsva: true,
+ cmyk: true,
+ input: true
+ }
+ }
+ })
+
+ // auto size window
+ let contentWidth = document.getElementsByClassName('pcr-app')[0].getBoundingClientRect().width
+ let contentHeight = document.getElementsByClassName('pcr-app')[0].getBoundingClientRect().height
+ colorPickerBox.resize(contentWidth + 8, contentHeight + 35) // TODO: use better way to get content height and width
+ colorPickerBox.show()
+
+ // create new canvas
+ let canvas = document.createElement('canvas')
+ canvas.style.display = 'none'
+
+ let x = ''
+ let y = ''
+
+ // when image clicked
+ viewer.image.addEventListener(
+ 'click',
+ function (e) {
+ if (IS_PICKER_OPEN) {
+ handleImageClickOnPicker(e, viewer, canvas, pickr, x, y, settings)
+ } else {
+ this.removeEventListener('click', arguments.callee)
+ }
+ },
+ false
+ )
+
+ // when mouse move
+ viewer.image.addEventListener(
+ 'mousemove',
+ function (e) {
+ if (IS_PICKER_OPEN) {
+ handleMouseMoveOnPicker(e, viewer, canvas, pickr, x, y)
+ } else {
+ this.removeEventListener('mousemove', arguments.callee)
+ }
+ },
+ false
+ )
+ } else {
+ return
+ }
+ }
+ },
+ details: settings.settings.details && {
+ show: isLocalFile ? 0 : 1,
+ size: 'large',
+ click: async function () {
+ if (!IS_DETAILS_OPEN) {
+ IS_DETAILS_OPEN = true
+ try {
+ new WinBox('Details', {
+ class: [
+ //"no-scrollbar",
+ 'no-max',
+ 'no-min',
+ 'no-full',
+ 'no-resize',
+ 'no-animation'
+ ],
+ index: 9999,
+ background: 'rgba(0,0,0,0.9)',
+ x: '20px',
+ y: '20px',
+ width: '350px',
+ height: '40%',
+ html: ``,
+ onclose: function () {
+ IS_DETAILS_OPEN = false
+ }
+ })
+ } catch (error) {
+ console.error(error)
+ }
+ }
+
+ let img2 = viewer.image
+
+ const fileImg = await fetch(img2.src).then(r => r.blob())
+ let fileSizeMB = fileImg.size / 1024 / 1024
+
+ let imgDetails = {
+ width: img2.naturalWidth,
+ height: img2.naturalHeight,
+ filesize: fileSizeMB.toFixed(2) + ' MB'
+ }
+
+ EXIF.getData(img2, function () {
+ let allMetaData = EXIF.getAllTags(this)
+ // add all metadata to wrapper
+ // let wrapper = document.getElementById('details-wrapper');
+
+ delete allMetaData.ImageWidth
+ delete allMetaData.ImageHeight
+ delete allMetaData.thumbnail
+
+ allMetaData = { Width: imgDetails.width + 'px', Height: imgDetails.height + 'px', 'File size': imgDetails.filesize, ...allMetaData }
+
+ let el = document.querySelector('#details-wrapper')
+ el.innerHTML = jsonViewer(allMetaData, true)
+
+ // convert to string
+ //let metaDataString = JSON.stringify(allMetaData, null, "\t");
+
+ // add string inside wrapper
+ //wrapper.innerHTML = metaDataString;
+ })
+ }
+ },
+ theme: settings.settings.theme && {
+ show: 1,
+ size: 'large',
+ click: function () {
+ // blur --> light --> dark
+ changeTheme(viewer.image.src, settings)
+ }
+ },
+ print: settings.settings.print && {
+ show: isLocalFile ? 0 : 1,
+ size: 'large',
+ click: function () {
+ printImage(viewer.image)
+ }
+ },
+ ocr: settings.settings.ocr && {
+ show: 1,
+ size: 'large',
+ click: function () {
+ let v = viewer
+ let url = viewer.image.src
+ let width = viewer.image.width
+ let height = viewer.image.height
+
+ let ocrPreviewBox = new WinBox('Image To Text: Select Region', {
+ id: 'ocr-preview',
+ class: WINBOX_CLASSES,
+ modal: false,
+ index: 9999,
+ x: 'center',
+ y: 'center',
+ width: width + 7,
+ height: height + 40,
+ background: 'rgba(0,0,0,0.9)',
+ html: ``,
+ onclose: function () {
+ document.querySelector('#ocr-preview').remove()
+ document.querySelector('#ocr-settings').remove()
+ }
+ })
+ ocrPreviewBox.show()
+ let ocrControlBox = new WinBox('Image To Text: Settings', {
+ id: 'ocr-settings',
+ class: WINBOX_CLASSES,
+ modal: false,
+ index: 9999,
+ x: '10px',
+ y: 'bottom',
+ top: '10px',
+ bottom: '10px',
+ right: '10px',
+ left: '10px',
+ width: '250px',
+ height: '160px',
+ background: 'rgba(0,0,0,0.9)',
+ html: `
+
+
Select Language
+
+
+
+
+
+
`,
+ onclose: function () {
+ document.querySelector('#ocr-preview').remove()
+ document.querySelector('#ocr-settings').remove()
+ document.querySelector('#ocr-result-box').remove()
+ }
+ })
+ ocrControlBox.show()
+ let imgCropper = tinycrop.create({
+ parent: '#parent-crop',
+ image: url,
+ bounds: {
+ width: width,
+ height: height
+ },
+ backgroundColors: ['#fff', '#f3f3f3'],
+ selection: {
+ color: '#212121CC',
+ activeColor: '#ff0000CC',
+ minWidth: 10,
+ minHeight: 10,
+ x: v.image.naturalWidth / 2 - width / 2,
+ y: v.image.naturalHeight / 2 - height / 2,
+ width: width,
+ height: height
+ },
+ onInit: () => {
+ console.log('Initialised')
+ }
+ })
+
+ let region // contains the cropped region
+ imgCropper.on('change', r => {
+ region = r
+ })
+
+ Object.keys(ocrLangList).forEach(function (key) {
+ let option = document.createElement('option')
+ option.value = ocrLangList[key]
+ option.text = key
+ if (key == 'English') {
+ option.selected = true
+ }
+ document.querySelector('#ocr-languages').appendChild(option)
+ })
+ // when btn-extract-text clicked
+ document.getElementById('btn-extract-text').addEventListener('click', function () {
+ // get selected language
+ let selectedLang = document.querySelector('#ocr-languages').value
+
+ const cropRect = region
+ const canvas = document.createElement('canvas')
+ const context = canvas.getContext('2d')
+ const imageObj = new Image()
+ canvas.width = cropRect.width
+ canvas.height = cropRect.height
+ imageObj.src = url
+
+ imageObj.onload = function () {
+ context.drawImage(imageObj, cropRect.x, cropRect.y, cropRect.width, cropRect.height, 0, 0, cropRect.width, cropRect.height)
+ let ImgUrl = canvas.toDataURL()
+
+ console.log(ImgUrl)
+
+ // create html element with text
+ let x = document.createElement('div')
+ // set flex
+ x.style.display = 'flex'
+ // set element inner html
+ x.innerHTML = ` Extracting Text`
+
+ Toastify({
+ node: x,
+ duration: 999999,
+ newWindow: true,
+ close: false,
+ gravity: settings.settings.notification_gravity, // `top` or `bottom`
+ position: settings.settings.notification_position, // `left`, `center` or `right`
+ stopOnFocus: true, // Prevents dismissing of toast on hover
+ style: {
+ color: '#ffffff',
+ background: '#000000'
+ }
+ }).showToast()
+
+ // tesseract to ocr
+ Tesseract.recognize(ImgUrl, selectedLang, { logger: m => console.log(m) }).then(({ data: { text } }) => {
+ // remove all toasts
+ let toastifyElems = document.querySelectorAll('.toastify')
+ toastifyElems.forEach(element => {
+ element.remove()
+ })
+
+ let ocrResElem = document.querySelector('#ocr-textarea')
+ if (ocrResElem) {
+ // if exists, then update
+ ocrResElem.innerHTML = text
+ } else {
+ // create new winbox
+
+ document.querySelector('#ocr-preview').remove()
+ document.querySelector('#ocr-settings').remove()
+
+ let ocrResultBox = new WinBox('Result', {
+ id: 'ocr-result-box',
+ class: WINBOX_CLASSES,
+ index: 9999,
+ width: '500px',
+ height: '320px',
+ top: '10px',
+ bottom: '10px',
+ right: '10px',
+ left: '10px',
+ x: 'center',
+ y: 'center',
+
+ background: 'rgba(0,0,0,0.9)',
+ html: `
+
+
+
`
+ })
+
+ ocrResultBox.show()
+
+ // when btn-extract-text clicked
+ document.getElementById('btn-copytext').addEventListener('click', function () {
+ showNotification('📋 Copied to clipboard', '#ffffff', '#000000', settings)
+ copyToClipboard(document.querySelector('#ocr-textarea').value)
+ })
+ }
+ })
+ }
+ })
+ try {
+ } catch (error) {
+ console.error(error)
+ }
+
+ // // for each key in object ocr
+ // for (const [key, value] of Object.entries(ocrLangList)) {
+ // console.log(`${key}: ${value}`);
+ // }
+ }
+ },
+ photopea: settings.settings.photopea && {
+ show: isLocalFile ? 0 : 1,
+ size: 'large',
+ click: function () {
+ let currentUrl = window.location.href
+ // create html element with text
+ let x = document.createElement('div')
+ // set flex
+ x.style.display = 'flex'
+ // set element inner html
+ x.innerHTML = ` Opening in Photopea... Please wait`
+
+ Toastify({
+ node: x,
+ duration: 999999,
+ newWindow: true,
+ close: false,
+ gravity: settings.settings.notification_gravity, // `top` or `bottom`
+ position: settings.settings.notification_position, // `left`, `center` or `right`
+ stopOnFocus: true, // Prevents dismissing of toast on hover
+ style: {
+ color: '#ffffff',
+ background: '#000000'
+ }
+ }).showToast()
+
+ // upload image to imgbb
+ // NB: expiration time is 60 seconds
+ fetch(`https://api.imgbb.com/1/upload?expiration=60&key=${IMGBB_TOKEN}&image=${encodeURIComponent(currentUrl)}`)
+ .then(res => res.json())
+ .then(res => {
+ const uri = '{ "files" : [ "' + res.data.image.url + '" ] }'
+ const encoded = encodeURI(uri)
+ const urlEncoded = 'https://www.photopea.com/#' + encoded
+ // remove toast
+ let toastifyElems = document.querySelectorAll('.toastify')
+ toastifyElems.forEach(element => {
+ element.remove()
+ })
+
+ window.open(urlEncoded, '_blank').focus()
+
+ showNotification(`📂 Image opened in Photopea successfully`, '#ffffff', '#000000', settings)
+ })
+ }
+ },
+ tineye: settings.settings.tineye && {
+ show: isLocalFile ? 0 : 1,
+ size: 'large',
+ click: function () {
+ // toastify
+ let x = document.createElement('div')
+ // set flex
+ x.style.display = 'flex'
+ // set element inner html
+ x.innerHTML = ` Opening in TinEye... Please wait`
+
+ Toastify({
+ node: x,
+ duration: 1000,
+ newWindow: true,
+ close: false,
+ gravity: settings.settings.notification_gravity, // `top` or `bottom`
+ position: settings.settings.notification_position, // `left`, `center` or `right`
+ stopOnFocus: true, // Prevents dismissing of toast on hover
+ style: {
+ color: '#ffffff',
+ background: '#000000'
+ }
+ }).showToast()
+
+ setTimeout(function () {
+ let currentUrl = encodeURIComponent(window.location.href)
+ let action_url = 'http://tineye.com/search?url=' + currentUrl
+ window.open(action_url, '_blank').focus()
+ }, 1000)
+ }
+ },
+ qr: settings.settings.qr && {
+ show: isLocalFile ? 0 : 1,
+ size: 'large',
+ click: function () {
+ // show loading toast
+ let x = document.createElement('div')
+ // set flex
+ x.style.display = 'flex'
+ // set element inner html
+ x.innerHTML = ` Scanning QR code... Please wait`
+
+ Toastify({
+ node: x,
+ duration: 9999,
+ newWindow: true,
+ close: false,
+ gravity: settings.settings.notification_gravity, // `top` or `bottom`
+ position: settings.settings.notification_position, // `left`, `center` or `right`
+ stopOnFocus: true, // Prevents dismissing of toast on hover
+ style: {
+ color: '#ffffff',
+ background: '#000000'
+ }
+ }).showToast()
+
+ // remove loading toast
+ setTimeout(function () {
+ let toastifyElems = document.querySelectorAll('.toastify')
+ toastifyElems.forEach(element => {
+ element.remove()
+ })
+
+ qrcode.callback = function (res) {
+ if (res instanceof Error) {
+ showNotification(`❌ No QR code found.`, '#ffffff', '#000000', settings)
+ } else {
+ //alert(res);
+ // show winbox
+
+ let ocrResultBox = new WinBox('QR Code Result', {
+ id: 'ocr-result-box',
+ class: WINBOX_CLASSES,
+ index: 9999,
+ width: '500px',
+ height: '165px',
+ top: '10px',
+ bottom: '10px',
+ right: '10px',
+ left: '10px',
+ x: 'center',
+ y: 'center',
+ background: 'rgba(0,0,0,0.9)',
+ html: `
+
+
+
+
`
+ })
+
+ ocrResultBox.show()
+
+ // when btn-extract-text clicked
+ document.getElementById('btn-copytext').addEventListener('click', function () {
+ showNotification('📋 Copied to clipboard', '#ffffff', '#000000', settings)
+ copyToClipboard(document.querySelector('#qr-textarea').value)
+ })
+ }
+ }
+ let b64Img = getBase64Image(viewer.image)
+ qrcode.decode(b64Img)
+ }, 500)
+ }
+ },
+ help: settings.settings.help && {
+ show: 1,
+ size: 'large',
+ click: function () {
+ if (!IS_HELP_OPEN) {
+ IS_HELP_OPEN = true
+
+ try {
+ new WinBox('Help', {
+ class: WINBOX_CLASSES,
+ index: 9999,
+ x: 'center',
+ y: 'center',
+ top: '10px',
+ bottom: '10px',
+ right: '10px',
+ left: '10px',
+ width: '700px',
+ height: '423px',
+ background: 'rgba(0,0,0,0.9)',
+ url: 'https://www.youtube-nocookie.com/embed/3p7Jrdx2jOc?autoplay=1&color=white&controls=0&disablekb=1&loop=1&modestbranding=1&rel=0&mute=1',
+ onclose: function () {
+ IS_HELP_OPEN = false
+ }
+ })
+
+ new WinBox('Shortcuts', {
+ class: WINBOX_CLASSES,
+ index: 9999,
+ x: 'right',
+ y: 'center',
+ top: '10px',
+ bottom: '10px',
+ right: '10px',
+ left: '10px',
+ width: '550px',
+ height: '90%',
+ background: 'rgba(0,0,0,0.9)',
+ url: chrome.runtime.getURL('pages/shortcuts.html'),
+ onclose: function () {
+ IS_HELP_OPEN = false
+ }
+ })
+ } catch (error) {
+ console.error(error)
+ }
+ }
+ }
+ },
+ settings: settings.settings.settings && {
+ show: 1,
+ size: 'large',
+ click: function () {
+ // open winbox
+ try {
+ new WinBox('Settings', {
+ class: WINBOX_CLASSES,
+ index: 9999,
+ x: 'center',
+ y: 'center',
+ top: '10px',
+ bottom: '10px',
+ right: '10px',
+ left: '10px',
+ width: '350px',
+ height: '400px',
+ background: 'rgba(0,0,0,0.9)',
+ url: chrome.runtime.getURL('pages/settings.html')
+ })
+ } catch (error) {
+ console.error(error)
+ }
+ }
+ },
+ about: settings.settings.about && {
+ show: 1,
+ size: 'large',
+ click: function () {
+ try {
+ new WinBox('About', {
+ class: WINBOX_CLASSES,
+ index: 9999,
+ x: 'center',
+ y: 'center',
+ width: '700px',
+ height: '500px',
+ background: 'rgba(0,0,0,0.9)',
+ url: chrome.runtime.getURL('pages/about.html')
+ })
+ } catch (error) {
+ console.error(error)
+ }
+ }
+ },
+ exit: settings.settings.exit && {
+ show: 1,
+ size: 'large',
+ click: function () {
+ let url = window.location.href
+ viewer.destroy()
+ document.querySelector('.blurry-bg').remove()
+ document.querySelector('img').style.display = 'block'
+ document.querySelectorAll('.winbox').forEach(function (el) {
+ el.remove()
+ })
+ // remove all style tags
+ let styleTags = document.querySelectorAll('style')
+ styleTags.forEach(function (el) {
+ el.remove()
+ })
+ document.querySelector('img').src = url
+ }
+ },
+ more: {
+ show: 1,
+ size: 'large',
+ click: function () {
+ // get all viewer buttons
+ let viewerButtons = document.querySelectorAll('div.viewer-toolbar > ul > li')
+
+ let btnsExceptMore = Array.prototype.slice.call(viewerButtons).filter(function (el) {
+ return !el.classList.contains('viewer-more')
+ })
+
+ btnsExceptMore.forEach(btn => {
+ // toggle display of each button
+
+ let cssObj = window.getComputedStyle(btn, null)
+ let display = cssObj.getPropertyValue('display')
+
+ if (display === 'none') {
+ btn.style.display = 'list-item'
+ btn.style.opacity = 1
+ // append class
+ btn.classList.add('fade-in-right')
+ } else {
+ btn.style.display = 'none'
+ btn.style.opacity = 0
+ }
+ })
+ }
+ }
+ },
+ ready() {
+ // hide all at start
+ if (settings.settings.hide_all_at_start) {
+ // get all viewer buttons
+ let viewerButtons = document.querySelectorAll('div.viewer-toolbar > ul > li')
+
+ let btnsExceptMore = Array.prototype.slice.call(viewerButtons).filter(function (el) {
+ return !el.classList.contains('viewer-more')
+ })
+
+ btnsExceptMore.forEach(btn => {
+ // toggle display of each button
+
+ let cssObj = window.getComputedStyle(btn, null)
+ let display = cssObj.getPropertyValue('display')
+
+ if (display === 'none') {
+ btn.style.display = 'list-item'
+ btn.style.opacity = 1
+ // append class
+ btn.classList.add('fade-in-right')
+ } else {
+ btn.style.display = 'none'
+ btn.style.opacity = 0
+ }
+ })
+ }
+
+ setTimeout(() => {
+ if (settings.settings.toolbar_position === 'top') {
+ viewer.move(0, 50)
+ }
+ }, 100)
+ }
+ })
+
+ let lightTheme = `
+ transition: all 0.5s ease;
+ background-image: none;
+ background-color: #ffffff;
+ filter: blur(0px);
+ -webkit-filter: blur(0px);
+ height: 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: cover;
+ width: 100vw;
+ height: 100vh;
+ transform: scale(1.3);
+ `
+
+ let darktheme = `
+ transition: all 0.5s ease;
+ background-image: none;
+ background-color: #0e1217;
+ filter: blur(0px);
+ -webkit-filter: blur(0px);
+ height: 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: cover;
+ width: 100vw;
+ height: 100vh;
+ transform: scale(1.3);
+ opacity: 0;
+ `
+
+ let blurrytheme = `
+ transition: none;
+ background-image: url(${imgElement.src});
+ background-color: none;
+ filter: blur(15px);
+ -webkit-filter: blur(15px);
+ height: 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: cover;
+ width: 100vw;
+ height: 100vh;
+ transform: scale(1.3);
+ opacity: 1;
+ `
+
+ let currentTheme = bg => {
+ if (bg === 'light') {
+ return lightTheme
+ } else if (bg === 'dark') {
+ return darktheme
+ }
+ return blurrytheme
+ }
+
+ // inject css
+ injectCSS(`
+ .blurry-bg {
+ ${currentTheme(BACKGROUND_TYPE)}
+ }
+ /* Make blur darker */
+ .blurry-bg:before {
+ content: '';
+ background-color: #000;
+ opacity: ${BACKGROUND_TYPE === 'blurred' ? 0.5 : 0};
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+ img{
+ display: none
+ }
+ .viewer-footer {
+ bottom: ${settings.settings.toolbar_position === 'bottom' ? '0px' : 'unset'} !important;
+ top: ${settings.settings.toolbar_position === 'top' ? '10px' : 'unset'} !important;
+ }
+ `)
+
+ // show the viewer
+ viewer.show()
+
+ setTippyText(tippyData)
+ }
+}
+
+/**
+ * Helper function - converts an svg element to a base64 string
+ * @param {svgElement} svgElement the svg element to convert
+ * @returns
+ */
+function svgToBase64(svgElement) {
+ let svgString = new XMLSerializer().serializeToString(svgElement)
+ let decoded = unescape(encodeURIComponent(svgString))
+ let base64 = btoa(decoded)
+ return `data:image/svg+xml;base64,${base64}`
+}
+
+/**
+ * Injects css into the page
+ * @param {string} css string to inject
+ * @returns
+ */
+function injectCSS(css) {
+ let head = document.getElementsByTagName('head')[0]
+ if (!head) {
+ return
+ }
+ let style = document.createElement('style')
+ style.innerHTML = DOMPurify.sanitize(css)
+ head.appendChild(style)
+}
+
+/**
+ * tippy.js text - add tooltips to viewer's toolbar
+ * @param {*} arrBtns array Of Buttons
+ */
+function setTippyText(arrBtns) {
+ window.tippyInstances = []
+
+ arrBtns.forEach(function (item) {
+ let instances = tippy(`#viewer0 > div.viewer-footer > div.viewer-toolbar > ul > li.viewer-${item.type}.viewer-large`, {
+ content: item.text,
+ inertia: true,
+ animation: 'scale',
+ theme: 'dark'
+ })
+ window.tippyInstances = tippyInstances.concat(instances)
+ })
+}
+
+/**
+ * Download image
+ * @param {HTMLElement} image Viewer Image
+ */
+function download(image) {
+ const a = document.createElement('a')
+ a.href = image.src
+ a.download = image.alt
+ document.body.appendChild(a)
+ a.click()
+ document.body.removeChild(a)
+}
+
+/**
+ *
+ * @param {viewer} viewer
+ * @param {string} url
+ * @param {*} width
+ * @param {*} height
+ */
+function crop(v, url, width, height) {
+ // create new winbox
+ let winbox = new WinBox('Crop Image', {
+ id: 'winbox-crop-image',
+ class: WINBOX_CLASSES,
+
+ width: width + 7,
+ // height + 10%
+ height: height + 40 + 36,
+ x: 'center',
+ y: 'center',
+ index: 9999,
+ background: 'rgba(0,0,0,0.9)',
+ html: `
+
+
+ `,
+ onclose: function () {
+ // reset viewer zoom
+ // v.zoom(0.5);
+ IS_CROP_OPEN = false
+ }
+ })
+
+ let imgCropper = tinycrop.create({
+ parent: '#parent-crop',
+ image: url,
+ bounds: {
+ width: width,
+ height: height
+ },
+ backgroundColors: ['#fff', '#f3f3f3'],
+ selection: {
+ color: '#212121CC',
+ activeColor: '#ff0000CC',
+ minWidth: 10,
+ minHeight: 10,
+ x: v.image.naturalWidth / 2 - width / 2,
+ y: v.image.naturalHeight / 2 - height / 2,
+ width: width,
+ height: height
+ },
+ onInit: () => {
+ console.log('Initialised')
+ }
+ })
+
+ let region // contains the cropped region
+ imgCropper.on('change', r => {
+ console.log('change', r)
+ region = r
+ })
+
+ // const image = document.getElementById('crop-img');
+
+ setTimeout(function () {
+ // get crop btn and add event listener
+ let cropBtn = document.getElementById('btn-crop-img')
+
+ cropBtn.addEventListener('click', function () {
+ const cropRect = region
+ const canvas = document.createElement('canvas')
+ const context = canvas.getContext('2d')
+ const imageObj = new Image()
+ canvas.width = cropRect.width
+ canvas.height = cropRect.height
+ imageObj.src = url
+ imageObj.onload = function () {
+ context.drawImage(imageObj, cropRect.x, cropRect.y, cropRect.width, cropRect.height, 0, 0, cropRect.width, cropRect.height)
+ let ImgUrl = canvas.toDataURL()
+ v.image.src = ImgUrl
+
+ switch (BACKGROUND_TYPE) {
+ case 'blurred':
+ injectCSS(`
+ .blurry-bg {
+ background-image: url("${ImgUrl}");
+ }`)
+ break
+ case 'light':
+ break
+ case 'dark':
+ break
+ default:
+ break
+ }
+
+ setTimeout(function () {
+ window.dispatchEvent(new Event('resize'))
+ IS_CROP_OPEN = false
+ winbox.close()
+ }, 100)
+ }
+
+ // image.addEventListener('load', () => {
+
+ // console.log(image)
+ // context.drawImage(
+ // //croppr.imageEl,
+ // v.element,
+ // cropRect.x,
+ // cropRect.y,
+ // cropRect.width,
+ // cropRect.height,
+ // 0,
+ // 0,
+ // canvas.width,
+ // canvas.height,
+ // );
+ // });
+
+ //
+
+ //v.image.src = ImgUrl;
+
+ // switch (BACKGROUND_TYPE) {
+ // case 'blurred':
+ // injectCSS(`
+ // .blurry-bg {
+ // background-image: url("${ImgUrl}");
+ // }`);
+ // break;
+ // case 'light':
+ // break;
+ // case 'dark':
+ // break;
+ // default:
+ // break;
+ // }
+
+ // setTimeout(function () {
+ // v.zoom(0.5);
+ // window.dispatchEvent(new Event('resize'));
+ // }, 100);
+
+ // //showNotification("Image cropped successfully", '#ffffff', '#000000', settings)
+ // IS_CROP_OPEN = false;
+ // winbox.close();
+ })
+ }, 100)
+}
+
+// canvas function
+function useCanvas(el, image, callback) {
+ el.width = image.width // img width
+ el.height = image.height // img height
+ // draw image in canvas tag
+ el.getContext('2d').drawImage(image, 0, 0, image.width, image.height)
+ return callback()
+}
+
+function componentToHex(c) {
+ let hex = c.toString(16)
+ return hex.length == 1 ? '0' + hex : hex
+}
+function rgbToHex(r, g, b) {
+ return '#' + componentToHex(r) + componentToHex(g) + componentToHex(b)
+}
+
+function findPos(obj) {
+ let curleft = 0,
+ curtop = 0
+ if (obj.offsetParent) {
+ do {
+ curleft += obj.offsetLeft
+ curtop += obj.offsetTop
+ } while ((obj = obj.offsetParent))
+ return { x: curleft, y: curtop }
+ }
+ return undefined
+}
+
+function resetColorPicker(winboxPicker, v) {
+ //console.log(e);
+}
+
+const handleImageClickOnPicker = (e, v, canvas, pickr, x, y, settings) => {
+ if (e.offsetX) {
+ x = e.offsetX
+ y = e.offsetY
+ }
+
+ console.log(settings)
+
+ useCanvas(canvas, v.image, () => {
+ // get image data
+ let p = canvas.getContext('2d').getImageData(x, y, 1, 1).data
+ // show info
+ pickr.setColor(rgbToHex(p[0], p[1], p[2]))
+ copyToClipboard(rgbToHex(p[0], p[1], p[2]))
+ showNotification(`${rgbToHex(p[0], p[1], p[2]).toUpperCase()} copied to clipboard`, getColorByBgColor(rgbToHex(p[0], p[1], p[2])), rgbToHex(p[0], p[1], p[2]), settings)
+ })
+}
+
+const handleMouseMoveOnPicker = (e, v, canvas, pickr, x, y) => {
+ if (e.offsetX) {
+ x = e.offsetX
+ y = e.offsetY
+ }
+ useCanvas(canvas, v.image, function () {
+ // get image data
+ let p = canvas.getContext('2d').getImageData(x, y, 1, 1).data
+ pickr.setColor(rgbToHex(p[0], p[1], p[2]))
+ })
+}
+
+/**
+ * Get color (black/white) depending on bgColor so it would be clearly seen.
+ * @param {string} bgColor
+ * @returns {string}
+ */
+function getColorByBgColor(bgColor) {
+ if (!bgColor) {
+ return ''
+ }
+ return parseInt(bgColor.replace('#', ''), 16) > 0xffffff / 2 ? '#000' : '#fff'
+}
+
+/**
+ * Copy string to clipboard
+ * @param {string} str - string to copy
+ */
+function copyToClipboard(textToCopy) {
+ // navigator clipboard api needs a secure context (https)
+ if (navigator.clipboard && window.isSecureContext) {
+ // navigator clipboard api method'
+ return navigator.clipboard.writeText(textToCopy)
+ } else {
+ // text area method
+ let textArea = document.createElement('textarea')
+ textArea.value = textToCopy
+ // make the textarea out of viewport
+ textArea.style.position = 'fixed'
+ textArea.style.left = '-999999px'
+ textArea.style.top = '-999999px'
+ document.body.appendChild(textArea)
+ textArea.focus()
+ textArea.select()
+ return new Promise((res, rej) => {
+ // here the magic happens
+ document.execCommand('copy') ? res() : rej()
+ textArea.remove()
+ })
+ }
+}
+
+function printImage(image) {
+ let strb64 = getBase64Image(image)
+ printJS(strb64, 'image')
+}
+
+/**
+ * Convert image to base64
+ * @param {*} img Image element
+ * @returns
+ */
+function getBase64Image(img) {
+ let canvas = document.createElement('canvas')
+ canvas.width = img.naturalWidth
+ canvas.height = img.naturalHeight
+ let ctx = canvas.getContext('2d')
+ ctx.drawImage(img, 0, 0)
+ return canvas.toDataURL()
+}
+
+function changeTheme(imgsrc, settings) {
+ let lightTheme = `background-image: url("data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-sun'%3E%3Ccircle cx='12' cy='12' r='5'%3E%3C/circle%3E%3Cline x1='12' y1='1' x2='12' y2='3'%3E%3C/line%3E%3Cline x1='12' y1='21' x2='12' y2='23'%3E%3C/line%3E%3Cline x1='4.22' y1='4.22' x2='5.64' y2='5.64'%3E%3C/line%3E%3Cline x1='18.36' y1='18.36' x2='19.78' y2='19.78'%3E%3C/line%3E%3Cline x1='1' y1='12' x2='3' y2='12'%3E%3C/line%3E%3Cline x1='21' y1='12' x2='23' y2='12'%3E%3C/line%3E%3Cline x1='4.22' y1='19.78' x2='5.64' y2='18.36'%3E%3C/line%3E%3Cline x1='18.36' y1='5.64' x2='19.78' y2='4.22'%3E%3C/line%3E%3C/svg%3E");`
+ let darkTheme = `background-image: url("data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-moon'%3E%3Cpath d='M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z'%3E%3C/path%3E%3C/svg%3E");`
+ let blurTheme = `background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-droplet'%3E%3Cpath d='M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z'%3E%3C/path%3E%3C/svg%3E"); `
+
+ switch (BACKGROUND_TYPE) {
+ case 'blurred':
+ showNotification('☀️ Light Background', '#000000', '#ffffff', settings)
+ injectCSS(`
+ .viewer-theme {
+ ${darkTheme}
+ }
+ .blurry-bg {
+ transition: all 0.5s ease;
+ background-image: none;
+ background-color: #ffffff;
+ filter: blur(0px);
+ -webkit-filter: blur(0px);
+ height: 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: cover;
+ width: 100vw;
+ height: 100vh;
+ transform: scale(1.3);
+ }
+ .blurry-bg:before {
+ opacity: 0;
+ }
+
+ `)
+ BACKGROUND_TYPE = 'light'
+ break
+ case 'light':
+ showNotification('🌑 Dark Background', '#ffffff', '#000000', settings)
+ injectCSS(`
+ .viewer-theme {
+ ${blurTheme}
+ }
+ .blurry-bg {
+ transition: all 0.5s ease;
+ background-image: none;
+ background-color: #0e1217;
+ filter: blur(0px);
+ -webkit-filter: blur(0px);
+ height: 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: cover;
+ width: 100vw;
+ height: 100vh;
+ transform: scale(1.3);
+ opacity: 0;
+ }
+ .blurry-bg:before {
+ opacity: 0;
+ }
+ `)
+ BACKGROUND_TYPE = 'dark'
+ break
+ case 'dark':
+ // change to blurred
+ showNotification('💧 Blurred Background', '#ffffff', '#404040', settings)
+ injectCSS(`
+ .viewer-theme {
+ ${lightTheme}
+ }
+ .blurry-bg {
+ transition: none;
+ background-image: url("${imgsrc}");
+ background-color: none;
+ filter: blur(15px);
+ -webkit-filter: blur(15px);
+ height: 100%;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: cover;
+ width: 100vw;
+ height: 100vh;
+ transform: scale(1.3);
+ opacity: 1;
+ }
+ .blurry-bg:before {
+ opacity: 0.5;
+ }`)
+ BACKGROUND_TYPE = 'blurred'
+ break
+ }
+}
+
+function showNotification(text, textColor, bgColor, settings) {
+ Toastify({
+ text: `${text}`,
+ duration: 3000,
+ newWindow: true,
+ close: false,
+ gravity: settings.settings.notification_gravity, // `top` or `bottom`
+ position: settings.settings.notification_position, // `left`, `center` or `right`
+ stopOnFocus: true, // Prevents dismissing of toast on hover
+ style: {
+ color: textColor,
+ background: bgColor
+ }
+ }).showToast()
+}
+
+// hardcoded toast position for the shortcut.html save button -- fix if possible
+function showNotificationShortcuts(text, textColor, bgColor) {
+
+ Toastify({
+ text: `${text}`,
+ duration: 3000,
+ newWindow: true,
+ close: false,
+ gravity: 'top', // `top` or `bottom`
+ position: 'right', // `left`, `center` or `right`
+ stopOnFocus: true, // Prevents dismissing of toast on hover
+ style: {
+ color: textColor,
+ background: bgColor,
+ }
+ }).showToast();
+}
+
+
+function jsonViewer(json, collapsible = false) {
+ let TEMPLATES = {
+ item: '',
+ itemCollapsible: '',
+ itemCollapsibleOpen: ''
+ }
+
+ function createItem(key, value, type) {
+ let element = TEMPLATES.item.replace('%KEY%', key)
+
+ if (type == 'string') {
+ element = element.replace('%VALUE%', '"' + value + '"')
+ } else {
+ element = element.replace('%VALUE%', value)
+ }
+
+ element = element.replace('%TYPE%', type)
+
+ return element
+ }
+
+ function createCollapsibleItem(key, value, type, children) {
+ let tpl = 'itemCollapsible'
+
+ if (collapsible) {
+ tpl = 'itemCollapsibleOpen'
+ }
+
+ let element = TEMPLATES[tpl].replace('%KEY%', key)
+
+ element = element.replace('%VALUE%', type)
+ element = element.replace('%TYPE%', type)
+ element = element.replace('%CHILDREN%', children)
+
+ return element
+ }
+
+ function handleChildren(key, value, type) {
+ let html = ''
+
+ for (let item in value) {
+ let _key = item,
+ _val = value[item]
+
+ html += handleItem(_key, _val)
+ }
+
+ return createCollapsibleItem(key, value, type, html)
+ }
+
+ function handleItem(key, value) {
+ let type = typeof value
+
+ if (typeof value === 'object') {
+ return handleChildren(key, value, type)
+ }
+
+ return createItem(key, value, type)
+ }
+
+ function parseObject(obj) {
+ let _result = ''
+
+ for (let item in obj) {
+ let key = item,
+ value = obj[item]
+
+ _result += handleItem(key, value)
+ }
+
+ _result += '
'
+
+ return _result
+ }
+
+ return parseObject(json)
+}
+
+// listen to messages from iframe
+window.addEventListener('message', function (message) {
+ if (message.data.type == "settings") {
+ let user_settings = message.data.settings
+ // save using chrome.storage
+ chrome.storage.sync.set({
+ settings: user_settings
+ }, function () {
+ // Notify that we saved.
+ showNotification('💾 Settings saved successfully', '#ffffff', '#000000', message.data);
+ setTimeout(() => {
+ // reload window after saving
+ window.location.reload();
+ }, 1000)
+ });
+ };
+
+ if (message.data.type == "shortcutHotkeys") {
+ let user_shortcutHotkeys = message.data.shortcutHotkeys
+ // save using chrome.storage
+ chrome.storage.sync.set({
+ shortcutHotkeys: user_shortcutHotkeys,
+ }, function () {
+ // Notify that we saved.
+ showNotificationShortcuts('💾 Shortcuts saved successfully', '#ffffff', '#000000', message.data);
+ setTimeout(() => {
+ // reload window after saving
+ window.location.reload();
+ }, 1000)
+ });
+ };
+});
+
+
+
diff --git a/js/lib/viewer.min.js b/js/lib/viewer.min.js
index 66f8d84..d6fecfe 100644
--- a/js/lib/viewer.min.js
+++ b/js/lib/viewer.min.js
@@ -1651,6 +1651,8 @@
}
},
dragstart: function dragstart(event) {
+ if (event.altKey) return;
+
if (event.target.localName === 'img') {
event.preventDefault();
}
@@ -1668,6 +1670,7 @@
return;
} // Prevent default behaviours as page zooming in touch devices.
+ if (event.altKey) return;
event.preventDefault();