diff --git a/frontend/src/app/routes/view/view.component.html b/frontend/src/app/routes/view/view.component.html index f172bfd..905b0a4 100644 --- a/frontend/src/app/routes/view/view.component.html +++ b/frontend/src/app/routes/view/view.component.html @@ -8,9 +8,28 @@ -
+
+ +
+ + Image Format + + + {{ format.value }} + + + +
+ +
+ +
+
diff --git a/frontend/src/app/routes/view/view.component.scss b/frontend/src/app/routes/view/view.component.scss index bd1ff2e..c89cb34 100644 --- a/frontend/src/app/routes/view/view.component.scss +++ b/frontend/src/app/routes/view/view.component.scss @@ -6,3 +6,7 @@ .content-border { padding-block: 1rem; } + +mat-form-field { + width: 100%; +} diff --git a/frontend/src/app/routes/view/view.component.ts b/frontend/src/app/routes/view/view.component.ts index 3725adb..c04ade7 100644 --- a/frontend/src/app/routes/view/view.component.ts +++ b/frontend/src/app/routes/view/view.component.ts @@ -1,8 +1,18 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { ImageLinks } from 'picsur-shared/dist/dto/image-links.dto'; -import { HasFailed } from 'picsur-shared/dist/types'; +import { + AnimMime, + FullMime, + ImageMime, + Mime2Ext, + SupportedAnimMimes, + SupportedImageMimes, + SupportedMimeCategory +} from 'picsur-shared/dist/dto/mimes.dto'; +import { HasFailed, HasSuccess } from 'picsur-shared/dist/types'; import { UUIDRegex } from 'picsur-shared/dist/util/common-regex'; +import { ParseMime } from 'picsur-shared/dist/util/parse-mime'; import { ImageService } from 'src/app/services/api/image.service'; import { UtilService } from 'src/app/util/util-module/util.service'; @@ -18,31 +28,72 @@ export class ViewComponent implements OnInit { private utilService: UtilService ) {} + private id: string; + private hasOriginal: boolean = false; + private masterMime: FullMime = { + mime: ImageMime.JPEG, + type: SupportedMimeCategory.Image, + }; + + public formatOptions: { + value: string; + key: string; + }[] = []; + + public setSelectedValue: string = ImageMime.JPEG; + public previewLink = ''; public imageLinks = new ImageLinks(); async ngOnInit() { const params = this.route.snapshot.paramMap; - const id = params.get('id') ?? ''; - if (!UUIDRegex.test(id)) { + + this.id = params.get('id') ?? ''; + if (!UUIDRegex.test(this.id)) { return this.utilService.quitError('Invalid image link'); } - const metadata = await this.imageService.GetImageMeta(id); - if (HasFailed(metadata)) { + const metadata = await this.imageService.GetImageMeta(this.id); + if (HasFailed(metadata)) return this.utilService.quitError(metadata.getReason()); - } - const hasOriginal = metadata.fileMimes.original !== undefined; this.previewLink = this.imageService.GetImageURL( - id, + this.id, metadata.fileMimes.master ); - this.imageLinks = this.imageService.CreateImageLinksFromID( - id, - hasOriginal ? null : metadata.fileMimes.master - ); + this.hasOriginal = metadata.fileMimes.original !== undefined; + + const masterMime = ParseMime(metadata.fileMimes.master); + if (HasSuccess(masterMime)) { + this.masterMime = masterMime; + } + + if (this.hasOriginal) { + this.setSelectedValue = 'original'; + } else { + if (this.masterMime.type === SupportedMimeCategory.Image) { + this.setSelectedValue = ImageMime.JPEG; + } else if (this.masterMime.type === SupportedMimeCategory.Animation) { + this.setSelectedValue = AnimMime.GIF; + } else { + this.setSelectedValue = metadata.fileMimes.master; + } + } + + this.selectedFormat(this.setSelectedValue); + this.updateFormatOptions(); + } + + selectedFormat(format: string) { + if (format === 'original') { + this.imageLinks = this.imageService.CreateImageLinksFromID(this.id, null); + } else { + this.imageLinks = this.imageService.CreateImageLinksFromID( + this.id, + format + ); + } } download() { @@ -56,4 +107,35 @@ export class ViewComponent implements OnInit { goBackHome() { this.router.navigate(['/']); } + + private updateFormatOptions() { + let newOptions: { + value: string; + key: string; + }[] = []; + if (this.hasOriginal) { + newOptions.push({ + value: 'Original', + key: 'original', + }); + } + + if (this.masterMime.type === SupportedMimeCategory.Image) { + newOptions.push( + ...SupportedImageMimes.map((mime) => ({ + value: Mime2Ext(mime)?.toUpperCase() ?? 'Error', + key: mime, + })) + ); + } else if (this.masterMime.type === SupportedMimeCategory.Animation) { + newOptions.push( + ...SupportedAnimMimes.map((mime) => ({ + value: Mime2Ext(mime)?.toUpperCase() ?? 'Error', + key: mime, + })) + ); + } + + this.formatOptions = newOptions; + } } diff --git a/frontend/src/app/routes/view/view.module.ts b/frontend/src/app/routes/view/view.module.ts index 7f6e6d2..f875115 100644 --- a/frontend/src/app/routes/view/view.module.ts +++ b/frontend/src/app/routes/view/view.module.ts @@ -1,7 +1,9 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; +import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon'; +import { MatSelectModule } from '@angular/material/select'; import { CopyFieldModule } from 'src/app/components/copy-field/copy-field.module'; import { FabModule } from 'src/app/components/fab/fab.module'; import { PicsurImgModule } from 'src/app/components/picsur-img/picsur-img.module'; @@ -14,9 +16,11 @@ import { ViewRoutingModule } from './view.routing.module'; CopyFieldModule, ViewRoutingModule, MatButtonModule, + MatSelectModule, + MatDividerModule, PicsurImgModule, MatIconModule, - FabModule + FabModule, ], }) export class ViewRouteModule {} diff --git a/frontend/src/app/services/api/image.service.ts b/frontend/src/app/services/api/image.service.ts index 76f5e85..98efa80 100644 --- a/frontend/src/app/services/api/image.service.ts +++ b/frontend/src/app/services/api/image.service.ts @@ -46,7 +46,10 @@ export class ImageService { }; } - public CreateImageLinksFromID(imageID: string, mime: string | null): ImageLinks { + public CreateImageLinksFromID( + imageID: string, + mime: string | null + ): ImageLinks { return this.CreateImageLinks(this.GetImageURL(imageID, mime)); } } diff --git a/frontend/src/app/util/util-module/util.service.ts b/frontend/src/app/util/util-module/util.service.ts index 047bf83..1e0f7ed 100644 --- a/frontend/src/app/util/util-module/util.service.ts +++ b/frontend/src/app/util/util-module/util.service.ts @@ -121,6 +121,7 @@ export class UtilService { new Blob([file.buffer], { type: file.mimeType }) ); a.download = file.name; + a.target = '_self'; a.click(); closeDialog(); diff --git a/shared/src/dto/mimes.dto.ts b/shared/src/dto/mimes.dto.ts index 5dee088..e125ad6 100644 --- a/shared/src/dto/mimes.dto.ts +++ b/shared/src/dto/mimes.dto.ts @@ -35,20 +35,20 @@ export interface FullMime { export const ImageMime2ExtMap: { [key in ImageMime]: string; } = { + [ImageMime.QOI]: 'qoi', [ImageMime.JPEG]: 'jpg', [ImageMime.PNG]: 'png', [ImageMime.WEBP]: 'webp', [ImageMime.TIFF]: 'tiff', [ImageMime.BMP]: 'bmp', // [ImageMime.ICO]: 'ico', - [ImageMime.QOI]: 'qoi', }; export const AnimMime2ExtMap: { [key in AnimMime]: string; } = { - [AnimMime.APNG]: 'apng', [AnimMime.GIF]: 'gif', + [AnimMime.APNG]: 'apng', }; export const Mime2ExtMap: {