Skip to content

Commit

Permalink
Implement output format conversion to JPEG/WEBP/PNG
Browse files Browse the repository at this point in the history
  • Loading branch information
Sija committed Mar 4, 2024
1 parent c81570b commit f1ead42
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 10 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -42,7 +42,7 @@ REST web API for the [libgphoto2](http://www.gphoto.org/) library. You can use i

#### `/cameras/:id/blob`

- `GET /cameras/:id/blob/*filepath[?download=true&as_jpeg=true&width=512&height=768]`
- `GET /cameras/:id/blob/*filepath[?download=true&format=jpeg/webp/png&width=512&height=768]`
- `DELETE /cameras/:id/blob/*filepath`

#### `/cameras/:id/zip`
Expand Down
58 changes: 52 additions & 6 deletions src/ext/kemal.cr
Expand Up @@ -45,10 +45,56 @@ end

private MAGICKLOAD_EXTENSIONS = %w(.arw .cin .cr2 .crw .nef .orf .raf .x3f)

def send_file_as_jpeg(env, file : GPhoto2::CameraFile, width : Int? = nil, height : Int? = nil, disposition = nil)
file_path = Path[file.path]
enum ImageOutputFormat
JPEG
WEBP
PNG

def self.from_path?(path : Path)
case path.extension.downcase
when ".jpeg", ".jpg" then JPEG
when ".webp" then WEBP
when ".png" then PNG
end
end

def extension
case self
in JPEG then ".jpg"
in WEBP then ".webp"
in PNG then ".png"
end
end

def mime_type
case self
in JPEG then "image/jpeg"
in WEBP then "image/webp"
in PNG then "image/png"
end
end

def to_slice(image : Vips::Image, **options)
case self
in JPEG then image.jpegsave_buffer(**options)
in WEBP then image.webpsave_buffer(**options)
in PNG then image.pngsave_buffer(**options)
end
end
end

def send_file_as(env, file : GPhoto2::CameraFile, format : ImageOutputFormat = :jpeg, width : Int? = nil, height : Int? = nil, disposition = nil)
path = Path[file.path]
ext = path.extension.downcase

same_type = (format.extension == ext)
if same_type && !(width || height)
send_file env, file,
disposition: disposition
return
end

if file_path.extension.downcase.in?(MAGICKLOAD_EXTENSIONS)
if ext.in?(MAGICKLOAD_EXTENSIONS)
image, _ = Vips::Image.magickload_buffer(file.to_slice)
else
image = Vips::Image.new_from_buffer(file.to_slice)
Expand All @@ -72,9 +118,9 @@ def send_file_as_jpeg(env, file : GPhoto2::CameraFile, width : Int? = nil, heigh

disposition ||= "inline"

send_file env, image.jpegsave_buffer,
mime_type: "image/jpeg",
filename: "#{file_path.stem}.jpg",
send_file env, format.to_slice(image),
mime_type: format.mime_type,
filename: "#{path.stem}#{format.extension}",
disposition: disposition
end
end
Expand Down
13 changes: 10 additions & 3 deletions src/gphoto2/web/routes.cr
Expand Up @@ -132,7 +132,10 @@ get "/cameras/:id/blob/*filepath" do |env|
filepath = env.params.url["filepath"]
path = Path.posix(filepath)

as_jpeg = env.params.query["as_jpeg"]? == "true"
if format = env.params.query["format"]?.presence
format = ImageOutputFormat.parse?(format) || raise ArgumentError.new \
"Format must be one of: #{ImageOutputFormat.values.join(", ", &.to_s.downcase)} or auto"
end

if width = env.params.query["width"]?.presence
width = width.to_i? || raise ArgumentError.new("Width must be an integer")
Expand All @@ -151,8 +154,12 @@ get "/cameras/:id/blob/*filepath" do |env|
if request_accepts_json?(env.request)
send_json env, file
else
if as_jpeg || width
send_file_as_jpeg env, file,
if format || width
format ||= ImageOutputFormat.from_path?(path)
format ||= ImageOutputFormat::JPEG

send_file_as env, file,
format: format,
width: width,
height: height,
disposition: disposition
Expand Down

0 comments on commit f1ead42

Please sign in to comment.