feature (plg_image_thumbnail): more efficient image thumbnailing

This commit is contained in:
Mickael Kerjean 2022-12-09 00:56:58 +11:00
parent ee15742fae
commit 468251d69a
26 changed files with 58 additions and 42 deletions

View file

@ -2,7 +2,6 @@ all:
make build_init
make build_frontend
GOARCH=amd64 GOOS=linux make build_backend
# GOARCH=arm GOARM=7 GOOS=linux make build_backend
build_init:
go generate -x ./server/...

View file

@ -0,0 +1 @@
db54aaaa47c9b08763d804e6a6e5f4bc0513512283e940bbbc9c0eb4948b3330

View file

@ -0,0 +1 @@
3356b3016e1b45654889399e78fee04eaeb29a03d0d7f8ab2465609cbf1ec20d

View file

@ -0,0 +1 @@
d1d02d84c18e18ce639afaf35335a476eea5deebc5aa31aeb45f052abcd1f31d

View file

@ -0,0 +1 @@
2a377fad44b4dd63581c7e5ec736705c4700ff278fec8c477685ca45953da57b

Binary file not shown.

View file

@ -0,0 +1 @@
1e0ea798cadb3ed4af0e562e4044acae98f4c6db822b354d3623039e5b42ece9

Binary file not shown.

View file

@ -0,0 +1 @@
198cc17684799587cee23fee02df161822cc26a34dfed3ac70a3e29632813ab8

View file

@ -29,7 +29,7 @@ func init() {
} {
Hooks.Register.Thumbnailer(mType, thumbnailBuilder{thumbnailRaw})
}
// TODO: Hooks.Register.ProcessFileContentBeforeSend for raw files rendering
Hooks.Register.ProcessFileContentBeforeSend(renderRaw)
}
func thumbnailPng(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
@ -72,9 +72,17 @@ func thumbnailRaw(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req
}
func renderRaw(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
query := req.URL.Query()
if query.Get("thumbnail") == "true" {
return reader, nil
} else if isRaw(GetMimeType(query.Get("path"))) == false {
return reader, nil
} else if query.Get("size") == "" {
return reader, nil
}
h := (*res).Header()
r, err := createThumbnailForRaw(reader)
// r, err := createExtractForRaw(reader)
r, err := createRenderingForRaw(reader, query.Get("size"))
if err != nil {
h.Set("Content-Type", "image/png")
return NewReadCloserFromBytes(placeholder), nil
@ -134,16 +142,15 @@ func (this *ThumbnailExecutable) verify() bool {
return this.isValid
}
func (this *ThumbnailExecutable) Execute(reader io.ReadCloser) (io.ReadCloser, error) {
func (this *ThumbnailExecutable) Execute(reader io.ReadCloser, params ...string) (io.ReadCloser, error) {
if this.verify() == false {
Log.Error("plg_image_thumbnail::execution abort after verification on '%s'", this.Name)
reader.Close()
return nil, ErrFilesystemError
}
// TODO: rate limit this
var buf bytes.Buffer
var errBuff bytes.Buffer
cmd := exec.Command("/tmp/" + this.Name)
cmd := exec.Command("/tmp/"+this.Name, params...)
cmd.Stdin = reader
cmd.Stdout = &buf
cmd.Stderr = &errBuff

View file

@ -15,7 +15,11 @@ func init() {
}
func createThumbnailForRaw(reader io.ReadCloser) (io.ReadCloser, error) {
return exeForRaw.Execute(reader)
return exeForRaw.Execute(reader, "200")
}
func createRenderingForRaw(reader io.ReadCloser, size string) (io.ReadCloser, error) {
return exeForRaw.Execute(reader, size)
}
func isRaw(mType string) bool {

View file

@ -5,9 +5,7 @@
#define JPEG_QUALITY 50
#define min(a, b) (a > b ? b : a)
int jpeg_to_jpeg(FILE* input, FILE* output) {
int jpeg_to_jpeg(FILE* input, FILE* output, int targetSize) {
#ifdef HAS_DEBUG
clock_t t;
t = clock();
@ -46,25 +44,25 @@ int jpeg_to_jpeg(FILE* input, FILE* output) {
image_min_size = min(jpeg_config_input.output_width, jpeg_config_input.output_height);
jpeg_config_input.scale_num = 1;
jpeg_config_input.scale_denom = 1;
if (image_min_size / 8 >= TARGET_SIZE) {
if (image_min_size / 8 >= targetSize) {
jpeg_config_input.scale_num = 1;
jpeg_config_input.scale_denom = 8;
} else if (image_min_size * 2 / 8 >= TARGET_SIZE) {
} else if (image_min_size * 2 / 8 >= targetSize) {
jpeg_config_input.scale_num = 1;
jpeg_config_input.scale_denom = 4;
} else if (image_min_size * 3 / 8 >= TARGET_SIZE) {
} else if (image_min_size * 3 / 8 >= targetSize) {
jpeg_config_input.scale_num = 3;
jpeg_config_input.scale_denom = 8;
} else if (image_min_size * 4 / 8 >= TARGET_SIZE) {
} else if (image_min_size * 4 / 8 >= targetSize) {
jpeg_config_input.scale_num = 4;
jpeg_config_input.scale_denom = 8;
} else if (image_min_size * 5 / 8 >= TARGET_SIZE) {
} else if (image_min_size * 5 / 8 >= targetSize) {
jpeg_config_input.scale_num = 5;
jpeg_config_input.scale_denom = 8;
} else if (image_min_size * 6 / 8 >= TARGET_SIZE) {
} else if (image_min_size * 6 / 8 >= targetSize) {
jpeg_config_input.scale_num = 6;
jpeg_config_input.scale_denom = 8;
} else if (image_min_size * 7 / 8 >= TARGET_SIZE) {
} else if (image_min_size * 7 / 8 >= targetSize) {
jpeg_config_input.scale_num = 7;
jpeg_config_input.scale_denom = 8;
}

View file

@ -4,7 +4,7 @@
void jpeg_size(FILE* infile, int* height, int* width);
int jpeg_to_jpeg(FILE* input, FILE* output);
int jpeg_to_jpeg(FILE* input, FILE* output, int targetSize);
int jpeg_to_webp(FILE* input, FILE* output);
int jpeg_to_webp(FILE* input, FILE* output, int targetSize);

View file

@ -8,7 +8,7 @@ static int MyWriter(const uint8_t* data, size_t data_size, const WebPPicture* co
return data_size ? (fwrite(data, data_size, 1, out) == 1) : 1;
}
int png_to_webp(FILE* input, FILE* output) {
int png_to_webp(FILE* input, FILE* output, int targetSize) {
WebPPicture picture;
#ifdef HAS_DEBUG
@ -79,9 +79,9 @@ int png_to_webp(FILE* input, FILE* output) {
return 1;
}
DEBUG("rescale start");
if (image.width > TARGET_SIZE && image.height > TARGET_SIZE) {
float ratioHeight = (float) image.height / TARGET_SIZE;
float ratioWidth = (float) image.width / TARGET_SIZE;
if (image.width > targetSize && image.height > targetSize) {
float ratioHeight = (float) image.height / targetSize;
float ratioWidth = (float) image.width / targetSize;
float ratio = ratioWidth > ratioHeight ? ratioHeight : ratioWidth;
if (!WebPPictureRescale(&picture, image.width / ratio, image.height / ratio)) {
DEBUG("ERR Rescale");
@ -97,7 +97,7 @@ int png_to_webp(FILE* input, FILE* output) {
return 0;
}
int png_to_png(FILE* input, FILE* output) {
int png_to_png(FILE* input, FILE* output, int targetSize) {
#ifdef HAS_DEBUG
clock_t t;
t = clock();

View file

@ -1,5 +1,5 @@
#include <stdio.h>
int png_to_webp(FILE* input, FILE* output);
int png_to_webp(FILE* input, FILE* output, int targetSize);
int png_to_png(FILE* input, FILE* output);
int png_to_png(FILE* input, FILE* output, int targetSize);

View file

@ -6,12 +6,12 @@
#define BUF_SIZE 1024 * 1024
int raw_to_jpeg(FILE* input, FILE* output) {
int raw_to_jpeg(FILE* input, FILE* output, int targetSize) {
#ifdef HAS_DEBUG
clock_t t;
t = clock();
#endif
char fname_in[32] = "/tmp/filestash.XXXXXX";
int _mkstemp_in = mkstemp(fname_in);
if (_mkstemp_in == -1) {
@ -35,12 +35,12 @@ int raw_to_jpeg(FILE* input, FILE* output) {
DEBUG("libraw open file");
if (libraw_open_file(raw, fname_in) != 0) {
ERROR("libraw_open_file");
libraw_close(raw);
libraw_close(raw);
fclose(f_in);
remove(fname_in);
return 1;
}
raw->params.output_tiff = 1;
DEBUG("libraw unpack thumb");
char fname_out[32] = "/tmp/filestash.XXXXXX";
@ -51,14 +51,14 @@ int raw_to_jpeg(FILE* input, FILE* output) {
fclose(f_in);
return 1;
}
if (libraw_unpack_thumb(raw) == 0 && raw->thumbnail.tformat == LIBRAW_THUMBNAIL_JPEG) {
DEBUG("has an embed thumbnail");
if (libraw_dcraw_thumb_writer(raw, fname_out) == 0) {
DEBUG("process thumbnail");
libraw_close(raw);
FILE* f_out = fdopen(_mkstemp_out, "r");
int err = jpeg_to_jpeg(f_out, output);
int err = jpeg_to_jpeg(f_out, output, targetSize);
fclose(f_out);
fclose(f_in);
remove(fname_in);
@ -78,5 +78,5 @@ int raw_to_jpeg(FILE* input, FILE* output) {
remove(fname_in);
remove(fname_out);
libraw_close(raw);
return 1;
return 1;
}

View file

@ -4,4 +4,4 @@
#include "utils.h"
#include "image_jpeg.h"
int raw_to_jpeg(FILE* input, FILE* output);
int raw_to_jpeg(FILE* input, FILE* output, int targetSize);

View file

@ -3,5 +3,3 @@
#include "utils.h"
#define JPEG_QUALITY 50
#define min(a, b) (a > b ? b : a)

View file

@ -2,5 +2,5 @@
#include "image_jpeg.h"
int main(int argc, char **argv) {
return jpeg_to_jpeg(stdin, stdout);
return jpeg_to_jpeg(stdin, stdout, 200);
}

View file

@ -2,5 +2,5 @@
#include "image_png.h"
int main(int argc, char **argv) {
return png_to_webp(stdin, stdout);
return png_to_webp(stdin, stdout, 200);
}

View file

@ -1,5 +1,9 @@
#include "image_raw.h"
int main(int args, const char **argv) {
return raw_to_jpeg(stdin, stdout);
int targetSize = 200;
if(args >= 2) {
targetSize = atoi(argv[1]);
}
return raw_to_jpeg(stdin, stdout, targetSize);
}

View file

@ -1,5 +1,3 @@
#define TARGET_SIZE 200
#define HAS_DEBUG 1
#if HAS_DEBUG == 1
#include <time.h>
@ -10,3 +8,5 @@
#endif
#define ERROR(r) (fprintf(stderr, "[ERROR:('" r "')]"))
#define min(a, b) (a > b ? b : a)