delete image and add blank page basics

pull/150/merge^2
iozeey 2 years ago
parent 6c38173e1e
commit 0c8ffa04c3

@ -23,5 +23,31 @@ module Api
) )
} }
end end
def del_image
template = Template.find(params[:template_id])
attachment_id = params[:attachment_id]
document_id = params[:documentId]
page_number = template.documents.find(document_id).preview_images.find_index { |pic| pic.id == attachment_id }
if page_number
Templates::ProcessDocument.delete_picture(template, attachment_id, page_number)
render json: { success: true, message: 'New blank image added successfully' }
else
page_number = "No image found for deletion"
render json: { success: false, message: "Error: #{page_number}" }, status: :unprocessable_entity
end
end
def add_new_image
byebug
template = Template.find(params[:template_id])
begin
Templates::ProcessDocument.upload_new_blank_image(template)
render json: { success: true, message: 'New blank image added successfully' }
rescue StandardError => e
render json: { success: false, message: "Error adding new blank image: #{e.message}" }, status: :unprocessable_entity
end
end
end end
end end

@ -742,7 +742,7 @@ export default {
headers: { 'Content-Type': 'application/json' } headers: { 'Content-Type': 'application/json' }
}) })
}, },
removeImage (imageId) { removeImage ({ item, imageId }) {
console.log(this.template.documents[0].preview_secured_images) console.log(this.template.documents[0].preview_secured_images)
// output: 0: {id: 26, name: 'preview_images', uuid: 'db2de68e-c52f-41e0-a743-550a5ba26ec0', record_type: 'ActiveStorage::Attachment', record_id: 25, } 1 : {id: 27, name: 'preview_images', uuid: '4f2cd882-95fb-4344-8571-78c9bb5a20aa', record_type: 'ActiveStorage::Attachment', record_id: 25, } 2: {id: 28, name: 'preview_images', uuid: '28bb656a-0799-4a73-b665-692aab2c690b', record_type: 'ActiveStorage::Attachment', record_id: 25, } length: 3, imageId: 27 // output: 0: {id: 26, name: 'preview_images', uuid: 'db2de68e-c52f-41e0-a743-550a5ba26ec0', record_type: 'ActiveStorage::Attachment', record_id: 25, } 1 : {id: 27, name: 'preview_images', uuid: '4f2cd882-95fb-4344-8571-78c9bb5a20aa', record_type: 'ActiveStorage::Attachment', record_id: 25, } 2: {id: 28, name: 'preview_images', uuid: '28bb656a-0799-4a73-b665-692aab2c690b', record_type: 'ActiveStorage::Attachment', record_id: 25, } length: 3, imageId: 27
// const indexToRemove = this.template.documents.findIndex(item => item.id === imageId) // const indexToRemove = this.template.documents.findIndex(item => item.id === imageId)
@ -750,17 +750,78 @@ export default {
// Check if the document has a preview_images array // Check if the document has a preview_images array
if (Array.isArray(document.preview_images)) { if (Array.isArray(document.preview_images)) {
// Find the index of the preview image with the matching id // Find the index of the preview image with the matching id
console.log('simple preview', document.preview_images, ': secured', document.preview_secured_images)
const indexToRemove = document.preview_images.findIndex( const indexToRemove = document.preview_images.findIndex(
(previewImage) => previewImage.id === imageId (previewImage) => previewImage.id === imageId
) )
// console.log('simple preview', document.preview_images, ': secured', document.preview_secured_images)
console.log(indexToRemove)
if (indexToRemove !== -1) { if (indexToRemove !== -1) {
document.preview_images.splice(indexToRemove, 1) // here I want to send call to a controller named template_document
// Optionally, emit a 'change' event if needed const documentId = document.id
// this.$emit('change'); const apiUrl = `/api/templates/${this.template.id}/documents/${documentId}/del_image`
fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
template: this.template.id,
attachment_id: imageId,
documentId
// page_number: document.preview_images.find(x => x.id === imageId).name
})
})
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`)
}
return response.json()
})
.then((data) => {
// remove from frontend
document.preview_images.splice(indexToRemove, 1)
console.log('Success:', data)
})
.catch((error) => {
console.error('Error:', error)
})
} }
} }
}) })
},
addBlankPage (item) {
console.log(this.sortedDocuments)
// console.log(this.template)
const documentId = item.id
console.log(documentId)
const apiUrl = `/api/templates/${this.template.id}/documents/${documentId}/add_new_image`
fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
template: this.template.id,
document: item
})
})
// this.baseFetch(`/api/templates/${this.templateId}/documents/add_new_image`, {
// method: 'POST',
// body: JSON.stringify({ template: this.template }),
// headers: { 'Content-Type': 'application/json' }
// })
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`)
}
return response.json()
})
.then((data) => {
console.log('Success:', data)
})
.catch((error) => {
console.error('Error:', error)
})
} }
} }
} }

@ -73,7 +73,7 @@
<button <button
class="btn border-base-200 bg-white text-base-content btn-xs rounded hover:text-base-100 hover:bg-base-content hover:border-base-content w-full transition-colors" class="btn border-base-200 bg-white text-base-content btn-xs rounded hover:text-base-100 hover:bg-base-content hover:border-base-content w-full transition-colors"
style="width: 24px; height: 24px" style="width: 24px; height: 24px"
@click.stop="$emit('remove-image', previewImage.id)" @click.stop="$emit('remove-image', { item, previewImageId: previewImage.id })"
> >
&times; &times;
</button> </button>

@ -10,15 +10,24 @@
width="20" width="20"
class="animate-spin" class="animate-spin"
/> />
<IconUpload v-else width="20" /> <IconUpload
<span v-if="isLoading"> Uploading... </span> v-else
<span v-else-if="isProcessing"> Processing... </span> width="20"
<span v-else> Add Document </span> />
</label> <span v-if="isLoading">
<label class="btn btn-outline w-full mt-2" @click="addBlankPage"> Uploading...
<span> Add blank page </span> </span>
<span v-else-if="isProcessing">
Processing...
</span>
<span v-else>
Add Document
</span>
</label> </label>
<form ref="form" class="hidden"> <form
ref="form"
class="hidden"
>
<input <input
:id="inputId" :id="inputId"
ref="input" ref="input"
@ -27,118 +36,111 @@
:accept="acceptFileTypes" :accept="acceptFileTypes"
multiple multiple
@change="upload" @change="upload"
/> >
</form> </form>
</div> </div>
</template> </template>
<script> <script>
import { IconUpload, IconInnerShadowTop } from "@tabler/icons-vue"; import { IconUpload, IconInnerShadowTop } from '@tabler/icons-vue'
import { PDFDocument, rgb } from "pdf-lib";
export default { export default {
name: "DocumentsUpload", name: 'DocumentsUpload',
components: { components: {
IconUpload, IconUpload,
IconInnerShadowTop, IconInnerShadowTop
}, },
inject: ["baseFetch"], inject: ['baseFetch'],
props: { props: {
templateId: { templateId: {
type: [Number, String], type: [Number, String],
required: true, required: true
}, },
acceptFileTypes: { acceptFileTypes: {
type: String, type: String,
required: false, required: false,
default: "image/*, application/pdf", default: 'image/*, application/pdf'
}, },
isDirectUpload: { isDirectUpload: {
type: Boolean, type: Boolean,
required: true, required: true,
default: false, default: false
}, }
}, },
emits: ["success"], emits: ['success'],
data() { data () {
return { return {
isLoading: false, isLoading: false,
isProcessing: false, isProcessing: false
}; }
}, },
computed: { computed: {
inputId() { inputId () {
return "el" + Math.random().toString(32).split(".")[1]; return 'el' + Math.random().toString(32).split('.')[1]
}, }
}, },
mounted() { mounted () {
if (this.isDirectUpload) { if (this.isDirectUpload) {
import("@rails/activestorage"); import('@rails/activestorage')
} }
}, },
methods: { methods: {
async upload() { async upload () {
this.isLoading = true; this.isLoading = true
if (this.isDirectUpload) { if (this.isDirectUpload) {
const { DirectUpload } = await import("@rails/activestorage"); const { DirectUpload } = await import('@rails/activestorage')
const blobs = await Promise.all( const blobs = await Promise.all(
Array.from(this.$refs.input.files).map(async (file) => { Array.from(this.$refs.input.files).map(async (file) => {
const upload = new DirectUpload( const upload = new DirectUpload(
file, file,
"/direct_uploads", '/direct_uploads',
this.$refs.input this.$refs.input
); )
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
upload.create((error, blob) => { upload.create((error, blob) => {
if (error) { if (error) {
console.error(error); console.error(error)
return reject(error); return reject(error)
} else { } else {
return resolve(blob); return resolve(blob)
} }
}); })
}).catch((error) => { }).catch((error) => {
console.error(error); console.error(error)
}); })
}) })
).finally(() => { ).finally(() => {
this.isLoading = false; this.isLoading = false
}); })
this.isProcessing = true; this.isProcessing = true
this.baseFetch(`/api/templates/${this.templateId}/documents`, { this.baseFetch(`/api/templates/${this.templateId}/documents`, {
method: "POST", method: 'POST',
body: JSON.stringify({ blobs }), body: JSON.stringify({ blobs }),
headers: { "Content-Type": "application/json" }, headers: { 'Content-Type': 'application/json' }
}).then(resp => resp.json()).then((data) => {
this.$emit('success', data)
this.$refs.input.value = ''
}).finally(() => {
this.isProcessing = false
}) })
.then((resp) => resp.json())
.then((data) => {
this.$emit("success", data);
this.$refs.input.value = "";
})
.finally(() => {
this.isProcessing = false;
});
} else { } else {
this.baseFetch(`/api/templates/${this.templateId}/documents`, { this.baseFetch(`/api/templates/${this.templateId}/documents`, {
method: "POST", method: 'POST',
body: new FormData(this.$refs.form), body: new FormData(this.$refs.form)
}).then(resp => resp.json()).then((data) => {
this.$emit('success', data)
this.$refs.input.value = ''
}).finally(() => {
this.isLoading = false
}) })
.then((resp) => resp.json())
.then((data) => {
this.$emit("success", data);
this.$refs.input.value = "";
})
.finally(() => {
this.isLoading = false;
});
} }
}, }
}, }
}; }
</script> </script>

@ -43,7 +43,10 @@ Rails.application.routes.draw do
end end
resources :templates, only: %i[update show index destroy] do resources :templates, only: %i[update show index destroy] do
resources :submissions, only: %i[index create] resources :submissions, only: %i[index create]
resources :documents, only: %i[create], controller: 'templates_documents' resources :documents, only: %i[create], controller: 'templates_documents'do
post 'add_new_image', on: :member
post 'del_image', on: :member
end
end end
end end

@ -105,11 +105,14 @@ module Templates
def generate_pdf_secured_preview_images(template, attachment, data) def generate_pdf_secured_preview_images(template, attachment, data)
ActiveStorage::Attachment.where(name: SECURED_ATTACHMENT_NAME, record: attachment).destroy_all ActiveStorage::Attachment.where(name: SECURED_ATTACHMENT_NAME, record: attachment).destroy_all
# delete field image from pdf document throught hexapdf
number_of_pages = PDF::Reader.new(StringIO.new(data)).pages.size - 1 number_of_pages = PDF::Reader.new(StringIO.new(data)).pages.size - 1
(0..number_of_pages).each do |page_number| (0..number_of_pages).each do |page_number|
pdf = Vips::Image.new_from_buffer(data, '', dpi: DPI, page: page_number) pdf = Vips::Image.new_from_buffer(data, '', dpi: DPI, page: page_number)
pdf = pdf.resize(MAX_WIDTH / pdf.width.to_f) pdf = pdf.resize(MAX_WIDTH / pdf.width.to_f)
redacted_boxes = template.fields.select { |field| field['type'] == 'redact' && field['areas'][0]['page'] == page_number } redacted_boxes = template.fields.select { |field| field['type'] == 'redact' && field['areas'][0]['page'] == page_number }
# deleted_page_field = template.fields.select { |field| field['type'] == 'deleted_page' && field['areas'][0]['page'] == page_number }
# break if !deleted_page_field.empty?
if !redacted_boxes.empty? if !redacted_boxes.empty?
redacted_boxes.each do |box| redacted_boxes.each do |box|
x = (box['areas'][0]['x'] * pdf.width).to_i x = (box['areas'][0]['x'] * pdf.width).to_i
@ -134,5 +137,50 @@ module Templates
end end
end end
def delete_picture(template, attachment_id, page_number)
attachment = ActiveStorage::Attachment.find_by(id: attachment_id)
byebug
return unless attachment
attachment.purge
deleted_page_field = {
'type' => 'deleted_page',
'areas' => [{
'page' => page_number,
'x' => 0,
'y' => 0,
'w' => 1,
'h' => 1
}]
}
template.fields << deleted_page_field
template.save!
end
def upload_new_blank_image(template)
existing_document = template.documents.first
blank_image = generate_blank_image
blank_blob = create_blob_from_image(blank_image)
upload_new_attachment(template, blank_blob, ATTACHMENT_NAME)
# puts '-----New blank image uploaded successfully!-----'
Rails.logger.info('New blank image uploaded successfully!')
rescue StandardError => e
Rails.logger.error("Error uploading new blank image: #{e.message}")
end
def generate_blank_image
height = 2000
Vips::Image.black(MAX_WIDTH, height)
end
def create_blob_from_image(image)
ActiveStorage::Blob.create_and_upload!(
io: StringIO.new(image.write_to_buffer(FORMAT, Q: Q, interlace: true)),
filename: "#{SecureRandom.uuid}#{FORMAT}",
metadata: { analyzed: true, identified: true, width: image.width, height: image.height }
)
end
def upload_new_attachment(template, blob, attachment_name)
template.documents.attach(blob)
template.documents.last.update!(name: attachment_name)
end
end end
end end

Loading…
Cancel
Save