From 4ba18690d7abd7eea086bb59e6cbcc8ead9e121a Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 6 Nov 2025 20:25:17 +0900 Subject: feat(frontend): EXIFフレーム機能 (#16725) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip * wip * Update ImageEffector.ts * Update image-label-renderer.ts * Update image-label-renderer.ts * wip * Update image-label-renderer.ts * wip * wip * wip * wip * wip * wip * wip * Update use-uploader.ts * Update watermark.ts * wip * wu * wip * Update image-frame-renderer.ts * wip * wip * Update image-frame-renderer.ts * Create ImageCompositor.ts * Update ImageCompositor.ts * wip * wip * Update ImageEffector.ts * wip * Update use-uploader.ts * wip * wip * wip * wip * Update fxs.ts * wip * wip * wip * Update CHANGELOG.md * wip * wip * Update MkImageEffectorDialog.vue * Update MkImageEffectorDialog.vue * Update MkImageFrameEditorDialog.vue * Update use-uploader.ts * improve error handling * Update use-uploader.ts * 🎨 * wip * wip * lazy load * lazy load * wip * wip * wip --- CHANGELOG.md | 2 + locales/index.d.ts | 176 ++++++- locales/ja-JP.yml | 49 +- packages/frontend/package.json | 1 + .../src/components/MkEmbedCodeGenDialog.vue | 23 +- .../src/components/MkImageEffectorDialog.Layer.vue | 12 +- .../src/components/MkImageEffectorDialog.vue | 87 ++-- .../src/components/MkImageFrameEditorDialog.vue | 509 +++++++++++++++++++++ .../components/MkWatermarkEditorDialog.Layer.vue | 2 +- .../src/components/MkWatermarkEditorDialog.vue | 162 ++++--- packages/frontend/src/composables/use-uploader.ts | 176 +++++-- packages/frontend/src/lib/ImageCompositor.ts | 313 +++++++++++++ packages/frontend/src/lib/pizzax.ts | 2 + .../src/pages/settings/drive.ImageFrameItem.vue | 113 +++++ .../src/pages/settings/drive.WatermarkItem.vue | 15 +- packages/frontend/src/pages/settings/drive.vue | 86 +++- packages/frontend/src/preferences/def.ts | 23 +- .../image-compositor-functions/blockNoise.glsl | 43 ++ .../image-compositor-functions/blockNoise.ts | 95 ++++ .../utility/image-compositor-functions/blur.glsl | 78 ++++ .../src/utility/image-compositor-functions/blur.ts | 93 ++++ .../image-compositor-functions/checker.glsl | 43 ++ .../utility/image-compositor-functions/checker.ts | 61 +++ .../chromaticAberration.glsl | 49 ++ .../chromaticAberration.ts | 39 ++ .../image-compositor-functions/colorAdjust.glsl | 82 ++++ .../image-compositor-functions/colorAdjust.ts | 77 ++++ .../image-compositor-functions/colorClamp.glsl | 29 ++ .../image-compositor-functions/colorClamp.ts | 48 ++ .../colorClampAdvanced.ts | 88 ++++ .../image-compositor-functions/distort.glsl | 30 ++ .../utility/image-compositor-functions/distort.ts | 65 +++ .../utility/image-compositor-functions/fill.glsl | 50 ++ .../src/utility/image-compositor-functions/fill.ts | 100 ++++ .../image-compositor-functions/grayscale.glsl | 22 + .../image-compositor-functions/grayscale.ts | 21 + .../utility/image-compositor-functions/invert.glsl | 23 + .../utility/image-compositor-functions/invert.ts | 43 ++ .../utility/image-compositor-functions/mirror.glsl | 26 ++ .../utility/image-compositor-functions/mirror.ts | 46 ++ .../image-compositor-functions/pixelate.glsl | 68 +++ .../utility/image-compositor-functions/pixelate.ts | 93 ++++ .../image-compositor-functions/polkadot.glsl | 75 +++ .../utility/image-compositor-functions/polkadot.ts | 102 +++++ .../utility/image-compositor-functions/stripe.glsl | 45 ++ .../utility/image-compositor-functions/stripe.ts | 73 +++ .../image-compositor-functions/tearing.glsl | 33 ++ .../utility/image-compositor-functions/tearing.ts | 83 ++++ .../image-compositor-functions/threshold.glsl | 23 + .../image-compositor-functions/threshold.ts | 52 +++ .../image-compositor-functions/zoomLines.glsl | 48 ++ .../image-compositor-functions/zoomLines.ts | 87 ++++ .../src/utility/image-effector/ImageEffector.ts | 482 ++----------------- .../frontend/src/utility/image-effector/fxs.ts | 82 ++-- .../src/utility/image-effector/fxs/blockNoise.glsl | 43 -- .../src/utility/image-effector/fxs/blockNoise.ts | 86 ---- .../src/utility/image-effector/fxs/blur.glsl | 78 ---- .../src/utility/image-effector/fxs/blur.ts | 83 ---- .../src/utility/image-effector/fxs/checker.glsl | 43 -- .../src/utility/image-effector/fxs/checker.ts | 54 --- .../image-effector/fxs/chromaticAberration.glsl | 49 -- .../image-effector/fxs/chromaticAberration.ts | 34 -- .../utility/image-effector/fxs/colorAdjust.glsl | 82 ---- .../src/utility/image-effector/fxs/colorAdjust.ts | 69 --- .../src/utility/image-effector/fxs/colorClamp.glsl | 29 -- .../src/utility/image-effector/fxs/colorClamp.ts | 43 -- .../image-effector/fxs/colorClampAdvanced.ts | 79 ---- .../src/utility/image-effector/fxs/distort.glsl | 30 -- .../src/utility/image-effector/fxs/distort.ts | 58 --- .../src/utility/image-effector/fxs/fill.glsl | 50 -- .../src/utility/image-effector/fxs/fill.ts | 89 ---- .../src/utility/image-effector/fxs/grayscale.glsl | 22 - .../src/utility/image-effector/fxs/grayscale.ts | 19 - .../src/utility/image-effector/fxs/invert.glsl | 23 - .../src/utility/image-effector/fxs/invert.ts | 37 -- .../src/utility/image-effector/fxs/mirror.glsl | 26 -- .../src/utility/image-effector/fxs/mirror.ts | 41 -- .../src/utility/image-effector/fxs/pixelate.glsl | 68 --- .../src/utility/image-effector/fxs/pixelate.ts | 83 ---- .../src/utility/image-effector/fxs/polkadot.glsl | 75 --- .../src/utility/image-effector/fxs/polkadot.ts | 92 ---- .../src/utility/image-effector/fxs/stripe.glsl | 45 -- .../src/utility/image-effector/fxs/stripe.ts | 66 --- .../src/utility/image-effector/fxs/tearing.glsl | 33 -- .../src/utility/image-effector/fxs/tearing.ts | 75 --- .../src/utility/image-effector/fxs/threshold.glsl | 23 - .../src/utility/image-effector/fxs/threshold.ts | 46 -- .../image-effector/fxs/watermarkPlacement.glsl | 147 ------ .../image-effector/fxs/watermarkPlacement.ts | 94 ---- .../src/utility/image-effector/fxs/zoomLines.glsl | 48 -- .../src/utility/image-effector/fxs/zoomLines.ts | 77 ---- .../image-frame-renderer/ImageFrameRenderer.ts | 270 +++++++++++ .../src/utility/image-frame-renderer/frame.glsl | 61 +++ .../src/utility/image-frame-renderer/frame.ts | 57 +++ packages/frontend/src/utility/watermark.ts | 218 --------- .../src/utility/watermark/WatermarkRenderer.ts | 332 ++++++++++++++ .../frontend/src/utility/watermark/watermark.glsl | 147 ++++++ .../frontend/src/utility/watermark/watermark.ts | 57 +++ packages/frontend/src/utility/webgl.ts | 11 + pnpm-lock.yaml | 18 + 100 files changed, 4655 insertions(+), 3003 deletions(-) create mode 100644 packages/frontend/src/components/MkImageFrameEditorDialog.vue create mode 100644 packages/frontend/src/lib/ImageCompositor.ts create mode 100644 packages/frontend/src/pages/settings/drive.ImageFrameItem.vue create mode 100644 packages/frontend/src/utility/image-compositor-functions/blockNoise.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/blockNoise.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/blur.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/blur.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/checker.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/checker.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/chromaticAberration.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/chromaticAberration.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/colorAdjust.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/colorAdjust.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/colorClamp.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/colorClamp.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/colorClampAdvanced.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/distort.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/distort.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/fill.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/fill.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/grayscale.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/grayscale.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/invert.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/invert.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/mirror.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/mirror.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/pixelate.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/pixelate.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/polkadot.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/polkadot.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/stripe.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/stripe.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/tearing.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/tearing.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/threshold.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/threshold.ts create mode 100644 packages/frontend/src/utility/image-compositor-functions/zoomLines.glsl create mode 100644 packages/frontend/src/utility/image-compositor-functions/zoomLines.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/blockNoise.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/blockNoise.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/blur.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/blur.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/checker.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/checker.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/chromaticAberration.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/chromaticAberration.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/colorAdjust.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/colorAdjust.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/colorClamp.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/colorClamp.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/colorClampAdvanced.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/distort.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/distort.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/fill.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/fill.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/grayscale.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/grayscale.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/invert.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/invert.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/mirror.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/mirror.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/pixelate.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/pixelate.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/polkadot.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/polkadot.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/stripe.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/stripe.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/tearing.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/tearing.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/threshold.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/threshold.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/watermarkPlacement.ts delete mode 100644 packages/frontend/src/utility/image-effector/fxs/zoomLines.glsl delete mode 100644 packages/frontend/src/utility/image-effector/fxs/zoomLines.ts create mode 100644 packages/frontend/src/utility/image-frame-renderer/ImageFrameRenderer.ts create mode 100644 packages/frontend/src/utility/image-frame-renderer/frame.glsl create mode 100644 packages/frontend/src/utility/image-frame-renderer/frame.ts delete mode 100644 packages/frontend/src/utility/watermark.ts create mode 100644 packages/frontend/src/utility/watermark/WatermarkRenderer.ts create mode 100644 packages/frontend/src/utility/watermark/watermark.glsl create mode 100644 packages/frontend/src/utility/watermark/watermark.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 211296bb4d..057ffd5566 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - Enhance: DockerのNode.jsが24.10.0に更新されました ### Client +- Feat: 画像にメタデータを含むフレームをつけられる機能 +- Enhance: プリセットを作成しなくても画像にウォーターマークを付与できるように - Enhance: 管理しているチャンネルの見分けがつきやすくなるように - Enhance: プロフィールへのリンクをユーザーポップアップのアバターに追加 - Enhance: ユーザーのノート、フォロー、フォロワーページへのリンクをユーザーポップアップに追加 diff --git a/locales/index.d.ts b/locales/index.d.ts index 43e31c16a1..e4ebfedd3d 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -5625,6 +5625,172 @@ export interface Locale extends ILocale { * あなたは管理者です */ "youAreAdmin": string; + /** + * フレーム + */ + "frame": string; + /** + * プリセット + */ + "presets": string; + /** + * ゼロ埋め + */ + "zeroPadding": string; + "_imageEditing": { + "_vars": { + /** + * ファイルのキャプション + */ + "caption": string; + /** + * ファイル名 + */ + "filename": string; + /** + * 拡張子無しファイル名 + */ + "filename_without_ext": string; + /** + * 撮影年 + */ + "year": string; + /** + * 撮影月 + */ + "month": string; + /** + * 撮影日 + */ + "day": string; + /** + * 撮影した時刻(時) + */ + "hour": string; + /** + * 撮影した時刻(分) + */ + "minute": string; + /** + * 撮影した時刻(秒) + */ + "second": string; + /** + * カメラ名 + */ + "camera_model": string; + /** + * レンズ名 + */ + "camera_lens_model": string; + /** + * 焦点距離 + */ + "camera_mm": string; + /** + * 焦点距離(35mm判換算) + */ + "camera_mm_35": string; + /** + * 絞り + */ + "camera_f": string; + /** + * シャッタースピード + */ + "camera_s": string; + /** + * ISO感度 + */ + "camera_iso": string; + /** + * 緯度 + */ + "gps_lat": string; + /** + * 経度 + */ + "gps_long": string; + }; + }; + "_imageFrameEditor": { + /** + * フレームの編集 + */ + "title": string; + /** + * 画像にフレームやメタデータを含んだラベルを追加して装飾できます。 + */ + "tip": string; + /** + * ヘッダー + */ + "header": string; + /** + * フッター + */ + "footer": string; + /** + * フチの幅 + */ + "borderThickness": string; + /** + * ラベルの幅 + */ + "labelThickness": string; + /** + * ラベルのスケール + */ + "labelScale": string; + /** + * 中央揃え + */ + "centered": string; + /** + * キャプション(大) + */ + "captionMain": string; + /** + * キャプション(小) + */ + "captionSub": string; + /** + * 利用可能な変数 + */ + "availableVariables": string; + /** + * 二次元コード + */ + "withQrCode": string; + /** + * 背景色 + */ + "backgroundColor": string; + /** + * 文字色 + */ + "textColor": string; + /** + * フォント + */ + "font": string; + /** + * セリフ + */ + "fontSerif": string; + /** + * サンセリフ + */ + "fontSansSerif": string; + /** + * 保存せずに終了しますか? + */ + "quitWithoutSaveConfirm": string; + /** + * 画像の読み込みに失敗しました + */ + "failedToLoadImage": string; + }; "_compression": { "_quality": { /** @@ -12354,7 +12520,7 @@ export interface Locale extends ILocale { "defaultPreset": string; "_watermarkEditor": { /** - * 画像にクレジット情報などのウォーターマークを追加することができます。 + * 画像にクレジット情報などのウォーターマークを追加できます。 */ "tip": string; /** @@ -12469,6 +12635,10 @@ export interface Locale extends ILocale { * 空欄にするとアカウントのURLになります */ "leaveBlankToAccountUrl": string; + /** + * 画像の読み込みに失敗しました + */ + "failedToLoadImage": string; }; "_imageEffector": { /** @@ -12487,6 +12657,10 @@ export interface Locale extends ILocale { * 設定項目はありません */ "nothingToConfigure": string; + /** + * 画像の読み込みに失敗しました + */ + "failedToLoadImage": string; "_fxs": { /** * 色収差 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 0e2ae63804..d0485af208 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1401,6 +1401,51 @@ widgets: "ウィジェット" deviceInfo: "デバイス情報" deviceInfoDescription: "技術的なお問い合わせの際に、以下の情報を併記すると問題の解決に役立つことがあります。" youAreAdmin: "あなたは管理者です" +frame: "フレーム" +presets: "プリセット" +zeroPadding: "ゼロ埋め" + +_imageEditing: + _vars: + caption: "ファイルのキャプション" + filename: "ファイル名" + filename_without_ext: "拡張子無しファイル名" + year: "撮影年" + month: "撮影月" + day: "撮影日" + hour: "撮影した時刻(時)" + minute: "撮影した時刻(分)" + second: "撮影した時刻(秒)" + camera_model: "カメラ名" + camera_lens_model: "レンズ名" + camera_mm: "焦点距離" + camera_mm_35: "焦点距離(35mm判換算)" + camera_f: "絞り" + camera_s: "シャッタースピード" + camera_iso: "ISO感度" + gps_lat: "緯度" + gps_long: "経度" + +_imageFrameEditor: + title: "フレームの編集" + tip: "画像にフレームやメタデータを含んだラベルを追加して装飾できます。" + header: "ヘッダー" + footer: "フッター" + borderThickness: "フチの幅" + labelThickness: "ラベルの幅" + labelScale: "ラベルのスケール" + centered: "中央揃え" + captionMain: "キャプション(大)" + captionSub: "キャプション(小)" + availableVariables: "利用可能な変数" + withQrCode: "二次元コード" + backgroundColor: "背景色" + textColor: "文字色" + font: "フォント" + fontSerif: "セリフ" + fontSansSerif: "サンセリフ" + quitWithoutSaveConfirm: "保存せずに終了しますか?" + failedToLoadImage: "画像の読み込みに失敗しました" _compression: _quality: @@ -3307,7 +3352,7 @@ _userLists: watermark: "ウォーターマーク" defaultPreset: "デフォルトのプリセット" _watermarkEditor: - tip: "画像にクレジット情報などのウォーターマークを追加することができます。" + tip: "画像にクレジット情報などのウォーターマークを追加できます。" quitWithoutSaveConfirm: "保存せずに終了しますか?" driveFileTypeWarn: "このファイルは対応していません" driveFileTypeWarnDescription: "画像ファイルを選択してください" @@ -3336,12 +3381,14 @@ _watermarkEditor: polkadotSubDotRadius: "サブドットの大きさ" polkadotSubDotDivisions: "サブドットの数" leaveBlankToAccountUrl: "空欄にするとアカウントのURLになります" + failedToLoadImage: "画像の読み込みに失敗しました" _imageEffector: title: "エフェクト" addEffect: "エフェクトを追加" discardChangesConfirm: "変更を破棄して終了しますか?" nothingToConfigure: "設定項目はありません" + failedToLoadImage: "画像の読み込みに失敗しました" _fxs: chromaticAberration: "色収差" diff --git a/packages/frontend/package.json b/packages/frontend/package.json index bd81d1d2c6..1ad3437e86 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -48,6 +48,7 @@ "estree-walker": "3.0.3", "eventemitter3": "5.0.1", "execa": "9.6.0", + "exifreader": "4.32.0", "frontend-shared": "workspace:*", "icons-subsetter": "workspace:*", "idb-keyval": "6.2.2", diff --git a/packages/frontend/src/components/MkEmbedCodeGenDialog.vue b/packages/frontend/src/components/MkEmbedCodeGenDialog.vue index 0cb8499699..4f16149caa 100644 --- a/packages/frontend/src/components/MkEmbedCodeGenDialog.vue +++ b/packages/frontend/src/components/MkEmbedCodeGenDialog.vue @@ -24,9 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only :leaveToClass="$style.transition_x_leaveTo" >
{filename} - {{ i18n.ts._imageEditing._vars.filename }}{filename_without_ext} - {{ i18n.ts._imageEditing._vars.filename_without_ext }}{caption} - {{ i18n.ts._imageEditing._vars.caption }}{year} - {{ i18n.ts._imageEditing._vars.year }}{month} - {{ i18n.ts._imageEditing._vars.month }}{day} - {{ i18n.ts._imageEditing._vars.day }}{hour} - {{ i18n.ts._imageEditing._vars.hour }}{minute} - {{ i18n.ts._imageEditing._vars.minute }}{second} - {{ i18n.ts._imageEditing._vars.second }}{0month} - {{ i18n.ts._imageEditing._vars.month }} ({{ i18n.ts.zeroPadding }}){0day} - {{ i18n.ts._imageEditing._vars.day }} ({{ i18n.ts.zeroPadding }}){0hour} - {{ i18n.ts._imageEditing._vars.hour }} ({{ i18n.ts.zeroPadding }}){0minute} - {{ i18n.ts._imageEditing._vars.minute }} ({{ i18n.ts.zeroPadding }}){0second} - {{ i18n.ts._imageEditing._vars.second }} ({{ i18n.ts.zeroPadding }}){camera_model} - {{ i18n.ts._imageEditing._vars.camera_model }}{camera_lens_model} - {{ i18n.ts._imageEditing._vars.camera_lens_model }}{camera_mm} - {{ i18n.ts._imageEditing._vars.camera_mm }}{camera_mm_35} - {{ i18n.ts._imageEditing._vars.camera_mm_35 }}{camera_f} - {{ i18n.ts._imageEditing._vars.camera_f }}{camera_s} - {{ i18n.ts._imageEditing._vars.camera_s }}{camera_iso} - {{ i18n.ts._imageEditing._vars.camera_iso }}{gps_lat} - {{ i18n.ts._imageEditing._vars.gps_lat }}{gps_long} - {{ i18n.ts._imageEditing._vars.gps_long }}