mirror of
https://github.com/docusealco/docuseal.git
synced 2026-06-23 04:10:11 +00:00
add redact color
This commit is contained in:
@@ -10,7 +10,7 @@ class TemplateDocumentsModifyController < ApplicationController
|
|||||||
params.require(:documents).map do |item|
|
params.require(:documents).map do |item|
|
||||||
item.permit(:attachment_uuid,
|
item.permit(:attachment_uuid,
|
||||||
pages: [:attachment_uuid, :page, :rotate,
|
pages: [:attachment_uuid, :page, :rotate,
|
||||||
{ redact: [%i[x y w h]], replaced_page: %i[attachment_uuid page] }]).to_h
|
{ redact: [%i[x y w h color]], replaced_page: %i[attachment_uuid page] }]).to_h
|
||||||
end
|
end
|
||||||
|
|
||||||
Templates::ModifyDocuments.call(@template, documents_layout)
|
Templates::ModifyDocuments.call(@template, documents_layout)
|
||||||
|
|||||||
@@ -36,7 +36,8 @@
|
|||||||
<div
|
<div
|
||||||
v-for="(rect, rectIndex) in page.redact"
|
v-for="(rect, rectIndex) in page.redact"
|
||||||
:key="`redact-${rectIndex}`"
|
:key="`redact-${rectIndex}`"
|
||||||
class="absolute bg-black"
|
class="absolute"
|
||||||
|
:class="rect.color === 'white' ? 'bg-white' : 'bg-black'"
|
||||||
:style="{
|
:style="{
|
||||||
left: `${rect.x * 100}%`,
|
left: `${rect.x * 100}%`,
|
||||||
top: `${rect.y * 100}%`,
|
top: `${rect.y * 100}%`,
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
<div
|
<div
|
||||||
v-for="(rect, rectIndex) in redactRects"
|
v-for="(rect, rectIndex) in redactRects"
|
||||||
:key="`rect-${rectIndex}`"
|
:key="`rect-${rectIndex}`"
|
||||||
class="absolute bg-black pointer-events-none"
|
class="absolute pointer-events-none"
|
||||||
|
:class="color === 'white' ? 'bg-white' : 'bg-black'"
|
||||||
:style="{
|
:style="{
|
||||||
left: `${rect.x * 100}%`,
|
left: `${rect.x * 100}%`,
|
||||||
top: `${rect.y * 100}%`,
|
top: `${rect.y * 100}%`,
|
||||||
@@ -47,6 +48,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-56 flex-none border-l px-4 py-4 space-y-2">
|
<div class="w-56 flex-none border-l px-4 py-4 space-y-2">
|
||||||
|
<div class="flex items-center justify-between mb-1">
|
||||||
|
<span class="text-sm pl-1">{{ t('color') }}</span>
|
||||||
|
<div
|
||||||
|
class="join rounded"
|
||||||
|
style="height: 28px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
v-for="option in colors"
|
||||||
|
:key="option"
|
||||||
|
class="btn btn-sm join-item !h-7 !min-h-0 bg-white input-bordered hover:border-base-content/20 hover:bg-base-100/50 px-2"
|
||||||
|
:class="{ '!bg-base-200': color === option }"
|
||||||
|
@click.prevent="color = option"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="block w-10 h-4 border border-base-content/30"
|
||||||
|
:style="{ backgroundColor: option }"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
||||||
:disabled="!hasRedactions && !wasReset"
|
:disabled="!hasRedactions && !wasReset"
|
||||||
@@ -122,11 +143,15 @@ export default {
|
|||||||
selectedNodes: {},
|
selectedNodes: {},
|
||||||
freeRects: [],
|
freeRects: [],
|
||||||
rects: [],
|
rects: [],
|
||||||
|
color: 'black',
|
||||||
wasReset: false,
|
wasReset: false,
|
||||||
marquee: null
|
marquee: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
colors () {
|
||||||
|
return ['black', 'white']
|
||||||
|
},
|
||||||
rotate () {
|
rotate () {
|
||||||
return this.page.rotate || 0
|
return this.page.rotate || 0
|
||||||
},
|
},
|
||||||
@@ -186,6 +211,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
|
if ((this.page.redact || []).some((rect) => rect.color === 'white')) {
|
||||||
|
this.color = 'white'
|
||||||
|
}
|
||||||
|
|
||||||
if (this.imagePage) {
|
if (this.imagePage) {
|
||||||
this.rects = (this.page.redact || []).map((rect) => ({ ...rect }))
|
this.rects = (this.page.redact || []).map((rect) => ({ ...rect }))
|
||||||
|
|
||||||
@@ -238,7 +267,17 @@ export default {
|
|||||||
return { x, y }
|
return { x, y }
|
||||||
},
|
},
|
||||||
apply () {
|
apply () {
|
||||||
this.$emit('apply', this.redactRects)
|
const rects = this.redactRects.map((rect) => {
|
||||||
|
const next = { x: rect.x, y: rect.y, w: rect.w, h: rect.h }
|
||||||
|
|
||||||
|
if (this.color === 'white') {
|
||||||
|
next.color = 'white'
|
||||||
|
}
|
||||||
|
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$emit('apply', rects)
|
||||||
},
|
},
|
||||||
reset () {
|
reset () {
|
||||||
this.wasReset = true
|
this.wasReset = true
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ const en = {
|
|||||||
flip_horizontal: 'Flip horizontal',
|
flip_horizontal: 'Flip horizontal',
|
||||||
flip_vertical: 'Flip vertical',
|
flip_vertical: 'Flip vertical',
|
||||||
there_is_no_text_to_redact_on_this_page: 'This page contains only images. Redact tool can be used only with text pages',
|
there_is_no_text_to_redact_on_this_page: 'This page contains only images. Redact tool can be used only with text pages',
|
||||||
|
color: 'Color',
|
||||||
reset: 'Reset',
|
reset: 'Reset',
|
||||||
upload_to_document: 'Upload to "{document}"',
|
upload_to_document: 'Upload to "{document}"',
|
||||||
replace_existing_document: 'Replace existing document',
|
replace_existing_document: 'Replace existing document',
|
||||||
@@ -351,6 +352,7 @@ const es = {
|
|||||||
flip_horizontal: 'Voltear horizontal',
|
flip_horizontal: 'Voltear horizontal',
|
||||||
flip_vertical: 'Voltear vertical',
|
flip_vertical: 'Voltear vertical',
|
||||||
there_is_no_text_to_redact_on_this_page: 'Esta página contiene solo imágenes. La herramienta de censura solo puede usarse con páginas de texto',
|
there_is_no_text_to_redact_on_this_page: 'Esta página contiene solo imágenes. La herramienta de censura solo puede usarse con páginas de texto',
|
||||||
|
color: 'Color',
|
||||||
reset: 'Restablecer',
|
reset: 'Restablecer',
|
||||||
upload_to_document: 'Subir a "{document}"',
|
upload_to_document: 'Subir a "{document}"',
|
||||||
replace_existing_document: 'Reemplazar documento existente',
|
replace_existing_document: 'Reemplazar documento existente',
|
||||||
@@ -597,6 +599,7 @@ const it = {
|
|||||||
flip_horizontal: 'Rifletti orizzontale',
|
flip_horizontal: 'Rifletti orizzontale',
|
||||||
flip_vertical: 'Rifletti verticale',
|
flip_vertical: 'Rifletti verticale',
|
||||||
there_is_no_text_to_redact_on_this_page: 'Questa pagina contiene solo immagini. Lo strumento di oscuramento può essere usato solo con pagine di testo',
|
there_is_no_text_to_redact_on_this_page: 'Questa pagina contiene solo immagini. Lo strumento di oscuramento può essere usato solo con pagine di testo',
|
||||||
|
color: 'Colore',
|
||||||
reset: 'Reimposta',
|
reset: 'Reimposta',
|
||||||
upload_to_document: 'Carica in "{document}"',
|
upload_to_document: 'Carica in "{document}"',
|
||||||
replace_existing_document: 'Sostituisci documento esistente',
|
replace_existing_document: 'Sostituisci documento esistente',
|
||||||
@@ -837,6 +840,7 @@ const pt = {
|
|||||||
flip_horizontal: 'Inverter horizontal',
|
flip_horizontal: 'Inverter horizontal',
|
||||||
flip_vertical: 'Inverter vertical',
|
flip_vertical: 'Inverter vertical',
|
||||||
there_is_no_text_to_redact_on_this_page: 'Esta página contém apenas imagens. A ferramenta de censura só pode ser usada com páginas de texto',
|
there_is_no_text_to_redact_on_this_page: 'Esta página contém apenas imagens. A ferramenta de censura só pode ser usada com páginas de texto',
|
||||||
|
color: 'Cor',
|
||||||
reset: 'Redefinir',
|
reset: 'Redefinir',
|
||||||
upload_to_document: 'Enviar para "{document}"',
|
upload_to_document: 'Enviar para "{document}"',
|
||||||
replace_existing_document: 'Substituir documento existente',
|
replace_existing_document: 'Substituir documento existente',
|
||||||
@@ -1083,6 +1087,7 @@ const fr = {
|
|||||||
flip_horizontal: 'Miroir horizontal',
|
flip_horizontal: 'Miroir horizontal',
|
||||||
flip_vertical: 'Miroir vertical',
|
flip_vertical: 'Miroir vertical',
|
||||||
there_is_no_text_to_redact_on_this_page: 'Cette page ne contient que des images. L\'outil de caviardage ne peut être utilisé qu\'avec des pages de texte',
|
there_is_no_text_to_redact_on_this_page: 'Cette page ne contient que des images. L\'outil de caviardage ne peut être utilisé qu\'avec des pages de texte',
|
||||||
|
color: 'Couleur',
|
||||||
reset: 'Réinitialiser',
|
reset: 'Réinitialiser',
|
||||||
upload_to_document: 'Téléverser dans "{document}"',
|
upload_to_document: 'Téléverser dans "{document}"',
|
||||||
replace_existing_document: 'Remplacer le document existant',
|
replace_existing_document: 'Remplacer le document existant',
|
||||||
@@ -1326,6 +1331,7 @@ const de = {
|
|||||||
flip_horizontal: 'Horizontal spiegeln',
|
flip_horizontal: 'Horizontal spiegeln',
|
||||||
flip_vertical: 'Vertikal spiegeln',
|
flip_vertical: 'Vertikal spiegeln',
|
||||||
there_is_no_text_to_redact_on_this_page: 'Diese Seite enthält nur Bilder. Das Schwärzungswerkzeug kann nur mit Textseiten verwendet werden',
|
there_is_no_text_to_redact_on_this_page: 'Diese Seite enthält nur Bilder. Das Schwärzungswerkzeug kann nur mit Textseiten verwendet werden',
|
||||||
|
color: 'Farbe',
|
||||||
reset: 'Zurücksetzen',
|
reset: 'Zurücksetzen',
|
||||||
upload_to_document: 'In "{document}" hochladen',
|
upload_to_document: 'In "{document}" hochladen',
|
||||||
replace_existing_document: 'Vorhandenes Dokument ersetzen',
|
replace_existing_document: 'Vorhandenes Dokument ersetzen',
|
||||||
@@ -1569,6 +1575,7 @@ const nl = {
|
|||||||
flip_horizontal: 'Horizontaal spiegelen',
|
flip_horizontal: 'Horizontaal spiegelen',
|
||||||
flip_vertical: 'Verticaal spiegelen',
|
flip_vertical: 'Verticaal spiegelen',
|
||||||
there_is_no_text_to_redact_on_this_page: 'Deze pagina bevat alleen afbeeldingen. De redactietool kan alleen worden gebruikt met tekstpagina\'s',
|
there_is_no_text_to_redact_on_this_page: 'Deze pagina bevat alleen afbeeldingen. De redactietool kan alleen worden gebruikt met tekstpagina\'s',
|
||||||
|
color: 'Kleur',
|
||||||
reset: 'Opnieuw instellen',
|
reset: 'Opnieuw instellen',
|
||||||
upload_to_document: 'Uploaden naar "{document}"',
|
upload_to_document: 'Uploaden naar "{document}"',
|
||||||
replace_existing_document: 'Bestaand document vervangen',
|
replace_existing_document: 'Bestaand document vervangen',
|
||||||
|
|||||||
+7
-4
@@ -737,7 +737,7 @@ class Pdfium
|
|||||||
left = rect['x'].to_f * width
|
left = rect['x'].to_f * width
|
||||||
top = height - (rect['y'].to_f * height)
|
top = height - (rect['y'].to_f * height)
|
||||||
|
|
||||||
[left, top - (rect['h'].to_f * height), left + (rect['w'].to_f * width), top]
|
[left, top - (rect['h'].to_f * height), left + (rect['w'].to_f * width), top, rect['color']]
|
||||||
end
|
end
|
||||||
|
|
||||||
unwrap_form_objects(rect_bounds)
|
unwrap_form_objects(rect_bounds)
|
||||||
@@ -982,7 +982,9 @@ class Pdfium
|
|||||||
end
|
end
|
||||||
|
|
||||||
def draw_redaction_rects(rect_bounds)
|
def draw_redaction_rects(rect_bounds)
|
||||||
rect_bounds.each do |left, bottom, right, top|
|
rect_bounds.each do |left, bottom, right, top, color|
|
||||||
|
next if color == 'white'
|
||||||
|
|
||||||
rect_object = Pdfium.FPDFPageObj_CreateNewRect(left, bottom, right - left, top - bottom)
|
rect_object = Pdfium.FPDFPageObj_CreateNewRect(left, bottom, right - left, top - bottom)
|
||||||
|
|
||||||
raise PdfiumError, 'Failed to create redaction rect' if rect_object.null?
|
raise PdfiumError, 'Failed to create redaction rect' if rect_object.null?
|
||||||
@@ -1057,7 +1059,7 @@ class Pdfium
|
|||||||
a, b, c, d, e, f = matrix
|
a, b, c, d, e, f = matrix
|
||||||
det = (a * d) - (b * c)
|
det = (a * d) - (b * c)
|
||||||
|
|
||||||
rect_bounds.filter_map do |left, bottom, right, top|
|
rect_bounds.filter_map do |left, bottom, right, top, color|
|
||||||
corners = [[left, bottom], [right, bottom], [left, top], [right, top]].map do |x, y|
|
corners = [[left, bottom], [right, bottom], [left, top], [right, top]].map do |x, y|
|
||||||
u = ((d * (x - e)) - (c * (y - f))) / det
|
u = ((d * (x - e)) - (c * (y - f))) / det
|
||||||
v = ((a * (y - f)) - (b * (x - e))) / det
|
v = ((a * (y - f)) - (b * (x - e))) / det
|
||||||
@@ -1075,7 +1077,8 @@ class Pdfium
|
|||||||
|
|
||||||
[px_left, px_top,
|
[px_left, px_top,
|
||||||
(xs.max.ceil - px_left).clamp(1, image_width - px_left),
|
(xs.max.ceil - px_left).clamp(1, image_width - px_left),
|
||||||
(ys.max.ceil - px_top).clamp(1, image_height - px_top)]
|
(ys.max.ceil - px_top).clamp(1, image_height - px_top),
|
||||||
|
color]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -299,19 +299,17 @@ module Templates
|
|||||||
else image
|
else image
|
||||||
end
|
end
|
||||||
|
|
||||||
ink = Array.new(image.bands, 0.0)
|
pixel_rects.each do |left, top, rect_width, rect_height, color|
|
||||||
|
image = image.draw_rect(redaction_ink(image.bands, color), left, top, rect_width, rect_height, fill: true)
|
||||||
pixel_rects.each do |left, top, rect_width, rect_height|
|
|
||||||
image = image.draw_rect(ink, left, top, rect_width, rect_height, fill: true)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
image.write_to_buffer('.jpg', Q: 50, strip: true)
|
image.write_to_buffer('.jpg', Q: 50, strip: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def draw_image_redaction(image, rects)
|
def draw_image_redaction(image, rects)
|
||||||
ink = Array.new(image.bands) { |band| band == 3 ? 255.0 : 0.0 }
|
|
||||||
|
|
||||||
rects.each do |rect|
|
rects.each do |rect|
|
||||||
|
ink = redaction_ink(image.bands, rect['color'])
|
||||||
|
|
||||||
left = (rect['x'].to_f * image.width).floor.clamp(0, image.width - 1)
|
left = (rect['x'].to_f * image.width).floor.clamp(0, image.width - 1)
|
||||||
top = (rect['y'].to_f * image.height).floor.clamp(0, image.height - 1)
|
top = (rect['y'].to_f * image.height).floor.clamp(0, image.height - 1)
|
||||||
rect_width = (rect['w'].to_f * image.width).ceil.clamp(1, image.width - left)
|
rect_width = (rect['w'].to_f * image.width).ceil.clamp(1, image.width - left)
|
||||||
@@ -323,6 +321,12 @@ module Templates
|
|||||||
image
|
image
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def redaction_ink(bands, color)
|
||||||
|
value = color == 'white' ? 255.0 : 0.0
|
||||||
|
|
||||||
|
Array.new(bands) { |band| band == 3 ? 255.0 : value }
|
||||||
|
end
|
||||||
|
|
||||||
def open_or_build_pdf(attachment, redact: nil, rotate: nil, pdf_size: nil, default_size: nil)
|
def open_or_build_pdf(attachment, redact: nil, rotate: nil, pdf_size: nil, default_size: nil)
|
||||||
data =
|
data =
|
||||||
if attachment.image?
|
if attachment.image?
|
||||||
|
|||||||
Reference in New Issue
Block a user