Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions app/javascript/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,23 @@
import "trix"
import "@rails/actiontext"
import { start } from "@rails/activestorage"
import piexif from "piexifjs"

start()

function arrayBufferToBinaryString(buf) {
var bytes = new Uint8Array(buf);
var str = "";
for (var i = 0; i < bytes.length; i++) str += String.fromCharCode(bytes[i]);
return str;
}

function binaryStringToBlob(str) {
var bytes = new Uint8Array(str.length);
for (var i = 0; i < str.length; i++) bytes[i] = str.charCodeAt(i);
return new Blob([bytes], { type: "image/jpeg" });
}

function compressToJpeg(file) {
return new Promise(function (resolve) {
var MAX = 1920, QUALITY = 0.82;
Expand All @@ -22,9 +36,30 @@ function compressToJpeg(file) {
var canvas = document.createElement("canvas");
canvas.width = w; canvas.height = h;
canvas.getContext("2d").drawImage(img, 0, 0, w, h);
canvas.toBlob(function (blob) { if (!blob) { resolve(file); return; }
canvas.toBlob(function (blob) {
if (!blob) { resolve(file); return; }
var name = file.name.replace(/\.[^.]+$/, ".jpg");
resolve(new File([blob], name, { type: "image/jpeg", lastModified: Date.now() }));
var isJpeg = file.type === "image/jpeg" || file.type === "image/jpg";
if (!isJpeg) {
resolve(new File([blob], name, { type: "image/jpeg", lastModified: Date.now() }));
return;
}
// Preserve EXIF from the original JPEG. Canvas drawImage already applies
// visual orientation, so reset the orientation tag to 1 (upright) to
// avoid double-rotation in viewers that honour EXIF.
Promise.all([file.arrayBuffer(), blob.arrayBuffer()]).then(function(bufs) {
try {
var srcStr = arrayBufferToBinaryString(bufs[0]);
var destStr = arrayBufferToBinaryString(bufs[1]);
var exifObj = piexif.load(srcStr);
if (exifObj["0th"]) exifObj["0th"][piexif.ImageIFD.Orientation] = 1;
var exifBytes = piexif.dump(exifObj);
var finalStr = piexif.insert(exifBytes, destStr);
resolve(new File([binaryStringToBlob(finalStr)], name, { type: "image/jpeg", lastModified: Date.now() }));
} catch (_) {
resolve(new File([blob], name, { type: "image/jpeg", lastModified: Date.now() }));
}
});
}, "image/jpeg", QUALITY);
};
img.onerror = function () { resolve(file); };
Expand Down
2 changes: 1 addition & 1 deletion app/views/active_storage/blobs/_blob.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>">
<% if blob.representable? %>
<%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %>
<%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ], saver: { strip: false }) %>
<% end %>

<figcaption class="attachment__caption">
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/check_ins/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
<!-- Thumbnail -->
<div class="flex-shrink-0 w-20 h-20">
<% if ci.image.attached? %>
<%= image_tag ci.image.variant(resize_to_limit: [80, 80]),
<%= image_tag ci.image.variant(resize_to_limit: [80, 80], saver: { strip: false }),
class: "w-20 h-20 object-cover border-2 border-black" %>
<% else %>
<div class="w-20 h-20 bg-gray-100 border-2 border-gray-300 flex items-center justify-center text-gray-400 text-xs">
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/check_ins/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
</div>
<div class="px-6 py-6">
<% if @check_in.image.attached? %>
<%= image_tag @check_in.image.variant(resize_to_limit: [800, 800]),
<%= image_tag @check_in.image.variant(resize_to_limit: [800, 800], saver: { strip: false }),
class: "max-w-full border-2 border-black" %>
<div class="mt-4">
<%= link_to "Download original", url_for(@check_in.image),
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/submissions/_table.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
<% blob = sub.media.blob %>
<% if blob.content_type.start_with?("image/") %>
<%= link_to url_for(sub.media), target: "_blank", rel: "noopener" do %>
<%= image_tag sub.media.variant(resize_to_limit: [64, 64]),
<%= image_tag sub.media.variant(resize_to_limit: [64, 64], saver: { strip: false }),
class: "w-16 h-16 object-cover border-2 border-black" %>
<% end %>
<% elsif blob.content_type.start_with?("video/") %>
Expand Down
4 changes: 2 additions & 2 deletions app/views/admin/submissions/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@

<% if blob.content_type.start_with?("image/") %>
<div class="relative group">
<%= image_tag submission.media.variant(resize_to_limit: [160, 160]),
<%= image_tag submission.media.variant(resize_to_limit: [160, 160], saver: { strip: false }),
class: "w-40 h-40 object-cover border-2 border-black" %>
<button
onclick='event.stopPropagation(); openMediaModal("image", <%= media_url.to_json %>, <%= modal_meta.to_json %>)'
Expand Down Expand Up @@ -318,7 +318,7 @@
<% if blob.content_type.start_with?("image/") %>
<div class="relative group inline-block">
<%= link_to url_for(sub.media), target: "_blank", rel: "noopener" do %>
<%= image_tag sub.media.variant(resize_to_limit: [64, 64]),
<%= image_tag sub.media.variant(resize_to_limit: [64, 64], saver: { strip: false }),
class: "w-16 h-16 object-cover border-2 border-black" %>
<% end %>
<button
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/submissions/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@
<td class="px-5 py-3">
<% if sub.media.attached? %>
<% if sub.media.blob.content_type.start_with?("image/") %>
<%= image_tag sub.media.variant(resize_to_limit: [48, 48]),
<%= image_tag sub.media.variant(resize_to_limit: [48, 48], saver: { strip: false }),
class: "w-12 h-12 object-cover border-2 border-black" %>
<% elsif sub.media.blob.content_type.start_with?("video/") %>
<span class="text-xs text-gray-500 font-mono">video</span>
Expand Down
2 changes: 1 addition & 1 deletion app/views/static_pages/home.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@
<% if @zone_first_submission&.media&.attached? %>
<% blob = @zone_first_submission.media.blob %>
<% if blob.content_type.start_with?("image/") %>
<%= image_tag @zone_first_submission.media.variant(resize_to_limit: [120, 120]),
<%= image_tag @zone_first_submission.media.variant(resize_to_limit: [120, 120], saver: { strip: false }),
class: "w-20 h-20 object-cover rounded-xl border-[3px] border-black flex-shrink-0" %>
<% elsif blob.content_type.start_with?("video/") %>
<video class="w-20 h-20 object-cover rounded-xl border-[3px] border-black bg-black flex-shrink-0" muted>
Expand Down
1 change: 1 addition & 0 deletions config/importmap.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Pin npm packages by running ./bin/importmap

pin "application"
pin "piexifjs", to: "https://cdn.jsdelivr.net/npm/piexifjs@1.0.6/+esm"
pin "mapkick/bundle", to: "mapkick.bundle.js"
pin "underscore", to: "https://cdn.jsdelivr.net/npm/underscore@1.13.6/underscore-min.js"
pin "markerclustererplus", to: "https://cdn.jsdelivr.net/npm/markerclustererplus@2.1.4/dist/markerclusterer.min.js"
Expand Down
Loading