2024-08-13 12:48:52 +03:00
|
|
|
import { Meta } from '../types'
|
2024-08-22 18:20:54 +02:00
|
|
|
import { PdfPage } from '../types/drawing.ts'
|
|
|
|
import { MOST_COMMON_MEDIA_TYPES } from './const.ts'
|
2024-08-13 12:48:52 +03:00
|
|
|
import { extractMarksFromSignedMeta } from './mark.ts'
|
2024-08-22 18:20:54 +02:00
|
|
|
import {
|
|
|
|
addMarks,
|
|
|
|
groupMarksByFileNamePage,
|
|
|
|
isPdf,
|
|
|
|
pdfToImages
|
|
|
|
} from './pdf.ts'
|
2024-08-13 12:48:52 +03:00
|
|
|
import JSZip from 'jszip'
|
|
|
|
|
2024-08-22 18:20:54 +02:00
|
|
|
export const getZipWithFiles = async (
|
2024-08-13 12:48:52 +03:00
|
|
|
meta: Meta,
|
2024-08-22 18:20:54 +02:00
|
|
|
files: { [filename: string]: SigitFile }
|
2024-08-13 12:48:52 +03:00
|
|
|
): Promise<JSZip> => {
|
|
|
|
const zip = new JSZip()
|
|
|
|
const marks = extractMarksFromSignedMeta(meta)
|
2024-08-16 12:01:41 +02:00
|
|
|
const marksByFileNamePage = groupMarksByFileNamePage(marks)
|
2024-08-13 12:48:52 +03:00
|
|
|
|
2024-08-21 17:07:29 +02:00
|
|
|
for (const [fileName, file] of Object.entries(files)) {
|
2024-10-09 11:51:26 +02:00
|
|
|
// Handle PDF Files, add marks
|
2024-10-11 16:16:59 +02:00
|
|
|
if (file.isPdf && fileName in marksByFileNamePage) {
|
2024-09-17 14:33:50 +02:00
|
|
|
const blob = await addMarks(file, marksByFileNamePage[fileName])
|
2024-10-09 11:51:26 +02:00
|
|
|
zip.file(`marked/${fileName}`, blob)
|
2024-08-21 17:07:29 +02:00
|
|
|
}
|
2024-10-09 11:51:26 +02:00
|
|
|
|
|
|
|
// Save original files
|
|
|
|
zip.file(`files/${fileName}`, file)
|
2024-08-13 12:48:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return zip
|
|
|
|
}
|
|
|
|
|
2024-08-22 18:20:54 +02:00
|
|
|
/**
|
|
|
|
* Converts a PDF ArrayBuffer to a generic PDF File
|
|
|
|
* @param arrayBuffer of a PDF
|
|
|
|
* @param fileName identifier of the pdf file
|
|
|
|
* @param type optional file type (defaults to pdf)
|
|
|
|
*/
|
|
|
|
export const toFile = (
|
|
|
|
arrayBuffer: ArrayBuffer,
|
|
|
|
fileName: string,
|
|
|
|
type: string = 'application/pdf'
|
|
|
|
): File => {
|
|
|
|
const blob = new Blob([arrayBuffer], { type })
|
|
|
|
return new File([blob], fileName, { type })
|
|
|
|
}
|
|
|
|
|
|
|
|
export class SigitFile extends File {
|
|
|
|
extension: string
|
|
|
|
isPdf: boolean
|
2024-08-22 18:48:03 +02:00
|
|
|
isImage: boolean
|
|
|
|
|
|
|
|
pages?: PdfPage[]
|
|
|
|
objectUrl?: string
|
2024-08-22 18:20:54 +02:00
|
|
|
|
|
|
|
constructor(file: File) {
|
|
|
|
super([file], file.name, { type: file.type })
|
|
|
|
this.isPdf = isPdf(this)
|
2024-08-22 18:48:03 +02:00
|
|
|
this.isImage = isImage(this)
|
2024-08-22 18:20:54 +02:00
|
|
|
this.extension = extractFileExtension(this.name)
|
|
|
|
}
|
|
|
|
|
|
|
|
async process() {
|
|
|
|
if (this.isPdf) this.pages = await pdfToImages(await this.arrayBuffer())
|
2024-08-22 18:48:03 +02:00
|
|
|
if (this.isImage) this.objectUrl = URL.createObjectURL(this)
|
2024-08-22 18:20:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const getSigitFile = async (file: File) => {
|
|
|
|
const sigitFile = new SigitFile(file)
|
|
|
|
// Process sigit file
|
|
|
|
// - generate pages for PDF files
|
2024-08-23 21:30:32 +02:00
|
|
|
// - generate ObjectRL for image files
|
2024-08-22 18:20:54 +02:00
|
|
|
await sigitFile.process()
|
|
|
|
return sigitFile
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Takes an ArrayBuffer and converts to Sigit's Internal File type
|
|
|
|
* @param arrayBuffer
|
|
|
|
* @param fileName
|
|
|
|
*/
|
|
|
|
export const convertToSigitFile = async (
|
|
|
|
arrayBuffer: ArrayBuffer,
|
|
|
|
fileName: string
|
|
|
|
): Promise<SigitFile> => {
|
|
|
|
const type = getMediaType(extractFileExtension(fileName))
|
|
|
|
const file = toFile(arrayBuffer, fileName, type)
|
|
|
|
const sigitFile = await getSigitFile(file)
|
|
|
|
return sigitFile
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param fileNames - List of filenames to check
|
|
|
|
* @returns List of extensions and if all are same
|
|
|
|
*/
|
|
|
|
export const extractFileExtensions = (fileNames: string[]) => {
|
|
|
|
const extensions = fileNames.reduce((result: string[], file: string) => {
|
|
|
|
const extension = file.split('.').pop()
|
|
|
|
if (extension) {
|
|
|
|
result.push(extension)
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
const isSame = extensions.every((ext) => ext === extensions[0])
|
|
|
|
|
|
|
|
return { extensions, isSame }
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param fileName - Filename to check
|
|
|
|
* @returns Extension string
|
|
|
|
*/
|
|
|
|
export const extractFileExtension = (fileName: string) => {
|
|
|
|
const parts = fileName.split('.')
|
|
|
|
return parts[parts.length - 1]
|
|
|
|
}
|
|
|
|
|
|
|
|
export const getMediaType = (extension: string) => {
|
|
|
|
return MOST_COMMON_MEDIA_TYPES.get(extension)
|
|
|
|
}
|
2024-08-22 18:48:03 +02:00
|
|
|
|
|
|
|
export const isImage = (file: File) => {
|
|
|
|
const validImageMediaTypes = [
|
|
|
|
'image/png',
|
|
|
|
'image/jpeg',
|
|
|
|
'image/jpg',
|
|
|
|
'image/gif',
|
|
|
|
'image/svg+xml',
|
|
|
|
'image/bmp',
|
|
|
|
'image/x-icon'
|
|
|
|
]
|
|
|
|
|
|
|
|
return validImageMediaTypes.includes(file.type.toLowerCase())
|
|
|
|
}
|