chore (maintenance): deprecate old thumbnail plugin

This commit is contained in:
MickaelK 2024-06-27 23:43:51 +10:00
parent 63ae5f2ed8
commit f4fe61c512
48 changed files with 0 additions and 1072 deletions

View file

@ -1,38 +0,0 @@
PLATFORM=linux
ARCH=amd64
all:
@make jpeg
@make png
@make raw
image_jpeg.o:
gcc -Wall -c src/image_jpeg.c -o src/image_jpeg.o
image_png.o:
gcc -Wall -c src/image_png.c -o src/image_png.o
image_raw.o:
gcc -Wall -c src/image_raw.c -o src/image_raw.o
jpeg: image_jpeg.o
gcc -static src/main_jpeg_to_jpeg.c src/image_jpeg.o -o dist/jpeg_$(PLATFORM)_$(ARCH).bin -l:libjpeg.a
sha256sum ./dist/jpeg_$(PLATFORM)_$(ARCH).bin | awk '{ printf $$1 }' > dist/jpeg_$(PLATFORM)_$(ARCH).bin.sha256
png: image_png.o
gcc -static -Wall src/main_png_to_webp.c src/image_png.o -o dist/png_$(PLATFORM)_$(ARCH).bin -l:libpng.a -l:libz.a -l:libwebp.a -lpthread -lm
sha256sum ./dist/png_$(PLATFORM)_$(ARCH).bin | awk '{ printf $$1 }' > dist/png_$(PLATFORM)_$(ARCH).bin.sha256
raw: image_raw.o image_jpeg.o
gcc -Wall -c src/main_raw_to_jpeg.c -o src/main_raw_to_jpeg.o
# libraw was configured like this: ./configure --disable-openmp --disable-lcms
g++ -static src/main_raw_to_jpeg.o src/image_raw.o src/image_jpeg.o -o dist/raw_$(PLATFORM)_$(ARCH).bin -l:libraw.a -l:libjpeg.a -l:libz.a -l:libstdc++.a -lm
sha256sum ./dist/raw_$(PLATFORM)_$(ARCH).bin | awk '{ printf $$1 }' > dist/raw_$(PLATFORM)_$(ARCH).bin.sha256
clean:
rm src/*.o dist/*_$(PLATFORM)_$(ARCH).bin* || true
test:
@gcc -Wall src/test.c -o test.bin -ljpeg -lpng -lz -lwebp -lpthread -lm -lraw
@./test.bin /home/mickael/Downloads/
@rm test.bin

View file

@ -1 +0,0 @@
db54aaaa47c9b08763d804e6a6e5f4bc0513512283e940bbbc9c0eb4948b3330

View file

@ -1 +0,0 @@
3356b3016e1b45654889399e78fee04eaeb29a03d0d7f8ab2465609cbf1ec20d

View file

@ -1 +0,0 @@
e4ec493a64ed971bad119bce2bb8f4790876a3bd41a30419dfca7fd66cc20830

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1 +0,0 @@
d1d02d84c18e18ce639afaf35335a476eea5deebc5aa31aeb45f052abcd1f31d

View file

@ -1 +0,0 @@
2a377fad44b4dd63581c7e5ec736705c4700ff278fec8c477685ca45953da57b

View file

@ -1 +0,0 @@
a67be4a057bf7053ea1f5a52b789cc92f2a176387d25ccfe4c2620484d4b0adf

View file

@ -1 +0,0 @@
1e0ea798cadb3ed4af0e562e4044acae98f4c6db822b354d3623039e5b42ece9

View file

@ -1 +0,0 @@
198cc17684799587cee23fee02df161822cc26a34dfed3ac70a3e29632813ab8

View file

@ -1 +0,0 @@
63e800f314d0392475dec307feaa26440eca116d27233c0a1171a0cc98e28fb4

View file

@ -1,160 +0,0 @@
package plg_image_thumbnail
import (
"bytes"
_ "embed"
"errors"
"fmt"
. "github.com/mickael-kerjean/filestash/server/common"
"io"
"net/http"
"os"
"os/exec"
"sync"
"time"
)
//go:embed dist/placeholder.png
var placeholder []byte
func init() {
Hooks.Register.Thumbnailer("image/png", thumbnailBuilder{thumbnailPng})
Hooks.Register.Thumbnailer("image/jpeg", thumbnailBuilder{thumbnailJpeg})
for _, mType := range []string{
"image/x-canon-cr2", "image/x-fuji-raf", "image/x-nikon-nef",
"image/x-nikon-nrw", "image/x-epson-erf",
} {
Hooks.Register.Thumbnailer(mType, thumbnailBuilder{thumbnailRaw})
}
Hooks.Register.ProcessFileContentBeforeSend(renderRaw)
}
func thumbnailPng(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
h := (*res).Header()
r, err := createThumbnailForPng(reader)
if err != nil {
h.Set("Content-Type", "image/png")
h.Set("Cache-Control", "max-age=1")
return NewReadCloserFromBytes(placeholder), nil
}
h.Set("Content-Type", "image/webp")
h.Set("Cache-Control", fmt.Sprintf("max-age=%d", 3600*12))
return r, nil
}
func thumbnailJpeg(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
h := (*res).Header()
r, err := createThumbnailForJpeg(reader)
if err != nil {
h.Set("Content-Type", "image/png")
h.Set("Cache-Control", "max-age=1")
return NewReadCloserFromBytes(placeholder), nil
}
h.Set("Content-Type", "image/jpeg")
h.Set("Cache-Control", fmt.Sprintf("max-age=%d", 3600*12))
return r, nil
}
func thumbnailRaw(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
h := (*res).Header()
r, err := createThumbnailForRaw(reader)
if err != nil {
h.Set("Content-Type", "image/png")
h.Set("Cache-Control", "max-age=1")
return NewReadCloserFromBytes(placeholder), nil
}
h.Set("Content-Type", "image/jpeg")
h.Set("Cache-Control", fmt.Sprintf("max-age=%d", 3600*12))
return r, nil
}
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 := createRenderingForRaw(reader, query.Get("size"))
if err != nil {
h.Set("Content-Type", "image/png")
return NewReadCloserFromBytes(placeholder), nil
}
h.Set("Content-Type", "image/jpeg")
h.Set("Cache-Control", fmt.Sprintf("max-age=%d", 3600*12))
return r, nil
}
type thumbnailBuilder struct {
fn func(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error)
}
func (this thumbnailBuilder) Generate(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
return this.fn(reader, ctx, res, req)
}
type ThumbnailExecutable struct {
Name string
Binary *[]byte
Checksum []byte
isValid bool
lastVerify time.Time
sync.Mutex
}
func (this ThumbnailExecutable) Init() {
p := "/tmp/" + this.Name
f, err := os.OpenFile(p, os.O_RDONLY, os.ModePerm)
if err != nil {
outFile, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY, os.ModePerm)
if err != nil {
Log.Warning("plg_image_thumbnail::init::run::openFile '%s'", this.Name)
return
}
outFile.Write(*this.Binary)
if err = outFile.Close(); err != nil {
Log.Warning("plg_image_thumbnail::init::run::close '%s'", this.Name)
return
}
}
f.Close()
}
func (this *ThumbnailExecutable) verify() bool {
this.Lock()
defer this.Unlock()
if time.Since(this.lastVerify) > 30*time.Second {
this.lastVerify = time.Now()
f, err := os.OpenFile("/tmp/"+this.Name, os.O_RDONLY, os.ModePerm)
if err == nil && bytes.Equal([]byte(HashStream(f, 0)), this.Checksum) {
this.isValid = true
}
}
return this.isValid
}
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
}
var buf bytes.Buffer
var errBuff bytes.Buffer
cmd := exec.Command("/tmp/"+this.Name, params...)
cmd.Stdin = reader
cmd.Stdout = &buf
cmd.Stderr = &errBuff
if err := cmd.Run(); err != nil {
reader.Close()
Log.Debug("plg_image_thumbmail::resize %s ERR %s", this.Name, string(errBuff.Bytes()))
return nil, errors.New(string(errBuff.Bytes()))
}
cmd.Wait()
reader.Close()
return NewReadCloserFromBytes(buf.Bytes()), nil
}

View file

@ -1,19 +0,0 @@
package plg_image_thumbnail
import (
"io"
)
var exeForJpeg ThumbnailExecutable = ThumbnailExecutable{
Name: "thumbnail_jpeg.bin",
Binary: &binaryThumbnailJpeg,
Checksum: checksumJpeg,
}
func init() {
exeForJpeg.Init()
}
func createThumbnailForJpeg(reader io.ReadCloser) (io.ReadCloser, error) {
return exeForJpeg.Execute(reader)
}

View file

@ -1,11 +0,0 @@
package plg_image_thumbnail
import (
_ "embed"
)
//go:embed dist/jpeg_linux_amd64.bin
var binaryThumbnailJpeg []byte
//go:embed dist/jpeg_linux_amd64.bin.sha256
var checksumJpeg []byte

View file

@ -1,11 +0,0 @@
package plg_image_thumbnail
import (
_ "embed"
)
//go:embed dist/jpeg_linux_arm.bin
var binaryThumbnailJpeg []byte
//go:embed dist/jpeg_linux_arm.bin.sha256
var checksumJpeg []byte

View file

@ -1,11 +0,0 @@
package plg_image_thumbnail
import (
_ "embed"
)
//go:embed dist/jpeg_linux_arm64.bin
var binaryThumbnailJpeg []byte
//go:embed dist/jpeg_linux_arm64.bin.sha256
var checksumJpeg []byte

View file

@ -1,19 +0,0 @@
package plg_image_thumbnail
import (
"io"
)
var exeForPng ThumbnailExecutable = ThumbnailExecutable{
Name: "thumbnail_png.bin",
Binary: &binaryThumbnailPng,
Checksum: checksumPng,
}
func init() {
exeForPng.Init()
}
func createThumbnailForPng(reader io.ReadCloser) (io.ReadCloser, error) {
return exeForPng.Execute(reader)
}

View file

@ -1,11 +0,0 @@
package plg_image_thumbnail
import (
_ "embed"
)
//go:embed dist/png_linux_amd64.bin
var binaryThumbnailPng []byte
//go:embed dist/png_linux_amd64.bin.sha256
var checksumPng []byte

View file

@ -1,11 +0,0 @@
package plg_image_thumbnail
import (
_ "embed"
)
//go:embed dist/png_linux_arm.bin
var binaryThumbnailPng []byte
//go:embed dist/png_linux_arm.bin.sha256
var checksumPng []byte

View file

@ -1,11 +0,0 @@
package plg_image_thumbnail
import (
_ "embed"
)
//go:embed dist/png_linux_arm64.bin
var binaryThumbnailPng []byte
//go:embed dist/png_linux_arm64.bin.sha256
var checksumPng []byte

View file

@ -1,54 +0,0 @@
package plg_image_thumbnail
import (
"io"
)
var exeForRaw ThumbnailExecutable = ThumbnailExecutable{
Name: "thumbnail_raw.bin",
Binary: &binaryThumbnailRaw,
Checksum: checksumRaw,
}
func init() {
exeForRaw.Init()
}
func createThumbnailForRaw(reader io.ReadCloser) (io.ReadCloser, error) {
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 {
switch mType {
case "image/x-tif":
case "image/x-canon-cr2":
case "image/x-canon-crw":
case "image/x-nikon-nef":
case "image/x-nikon-nrw":
case "image/x-sony-arw":
case "image/x-sony-sr2":
case "image/x-minolta-mrw":
case "image/x-minolta-mdc":
case "image/x-olympus-orf":
case "image/x-panasonic-rw2":
case "image/x-pentax-pef":
case "image/x-epson-erf":
case "image/x-raw":
case "image/x-x3f":
case "image/x-fuji-raf":
case "image/x-aptus-mos":
case "image/x-mamiya-mef":
case "image/x-hasselblad-3fr":
case "image/x-adobe-dng":
case "image/x-samsung-srw":
case "image/x-kodak-kdc":
case "image/x-kodak-dcr":
default:
return false
}
return true
}

View file

@ -1,11 +0,0 @@
package plg_image_thumbnail
import (
_ "embed"
)
//go:embed dist/raw_linux_amd64.bin
var binaryThumbnailRaw []byte
//go:embed dist/raw_linux_amd64.bin.sha256
var checksumRaw []byte

View file

@ -1,11 +0,0 @@
package plg_image_thumbnail
import (
_ "embed"
)
//go:embed dist/raw_linux_arm.bin
var binaryThumbnailRaw []byte
//go:embed dist/raw_linux_arm.bin.sha256
var checksumRaw []byte

View file

@ -1,11 +0,0 @@
package plg_image_thumbnail
import (
_ "embed"
)
//go:embed dist/raw_linux_arm64.bin
var binaryThumbnailRaw []byte
//go:embed dist/raw_linux_arm64.bin.sha256
var checksumRaw []byte

View file

@ -1,215 +0,0 @@
#include <stdio.h>
#include "utils.h"
#include "jpeglib.h"
// #include "webp/encode.h"
#define JPEG_QUALITY 50
int jpeg_to_jpeg(FILE* input, FILE* output, int targetSize) {
#ifdef HAS_DEBUG
clock_t t;
t = clock();
#endif
struct jpeg_decompress_struct jpeg_config_input;
struct jpeg_compress_struct jpeg_config_output;
struct jpeg_error_mgr jerr;
int jpeg_row_stride;
int image_min_size;
JSAMPARRAY buffer;
jpeg_config_input.err = jpeg_std_error(&jerr);
jpeg_config_output.err = jpeg_std_error(&jerr);
jpeg_config_input.dct_method = JDCT_IFAST;
jpeg_config_input.do_fancy_upsampling = FALSE;
jpeg_config_input.two_pass_quantize = FALSE;
jpeg_config_input.dither_mode = JDITHER_ORDERED;
jpeg_create_decompress(&jpeg_config_input);
jpeg_create_compress(&jpeg_config_output);
jpeg_stdio_src(&jpeg_config_input, input);
jpeg_stdio_dest(&jpeg_config_output, output);
DEBUG("after constructor decompress");
if(jpeg_read_header(&jpeg_config_input, TRUE) != JPEG_HEADER_OK) {
jpeg_destroy_decompress(&jpeg_config_input);
return 1;
}
DEBUG("after header read");
jpeg_config_input.dct_method = JDCT_IFAST;
jpeg_config_input.do_fancy_upsampling = FALSE;
jpeg_config_input.two_pass_quantize = FALSE;
jpeg_config_input.dither_mode = JDITHER_ORDERED;
jpeg_calc_output_dimensions(&jpeg_config_input);
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 >= targetSize) {
jpeg_config_input.scale_num = 1;
jpeg_config_input.scale_denom = 8;
} 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 >= targetSize) {
jpeg_config_input.scale_num = 3;
jpeg_config_input.scale_denom = 8;
} 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 >= targetSize) {
jpeg_config_input.scale_num = 5;
jpeg_config_input.scale_denom = 8;
} 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 >= targetSize) {
jpeg_config_input.scale_num = 7;
jpeg_config_input.scale_denom = 8;
}
DEBUG("start decompress");
if(jpeg_start_decompress(&jpeg_config_input) == FALSE) {
jpeg_destroy_decompress(&jpeg_config_input);
return 1;
}
DEBUG("processing image");
jpeg_row_stride = jpeg_config_input.output_width * jpeg_config_input.output_components;
jpeg_config_output.image_width = jpeg_config_input.output_width;
jpeg_config_output.image_height = jpeg_config_input.output_height;
jpeg_config_output.input_components = jpeg_config_input.num_components;
jpeg_config_output.in_color_space = JCS_RGB;
jpeg_set_defaults(&jpeg_config_output);
jpeg_set_quality(&jpeg_config_output, JPEG_QUALITY, TRUE);
jpeg_start_compress(&jpeg_config_output, TRUE);
buffer = (*jpeg_config_input.mem->alloc_sarray) ((j_common_ptr) &jpeg_config_input, JPOOL_IMAGE, jpeg_row_stride, 1);
while (jpeg_config_input.output_scanline < jpeg_config_input.output_height) {
// TODO: scanlines should return 1
jpeg_read_scanlines(&jpeg_config_input, buffer, 1);
jpeg_write_scanlines(&jpeg_config_output, buffer, 1);
}
DEBUG("end decompress");
jpeg_finish_decompress(&jpeg_config_input);
jpeg_destroy_decompress(&jpeg_config_input);
DEBUG("finish decompress");
jpeg_finish_compress(&jpeg_config_output);
DEBUG("final");
return 0;
}
/*
static int MyWriter(const uint8_t* data, size_t data_size,
const WebPPicture* const pic) {
FILE* const out = (FILE*)pic->custom_ptr;
return data_size ? (fwrite(data, data_size, 1, out) == 1) : 1;
}
int jpeg_to_webp(FILE* input, FILE* output) {
#ifdef HAS_DEBUG
clock_t t;
t = clock();
#endif
struct jpeg_decompress_struct jpeg_config_input;
struct jpeg_error_mgr jerr;
u_int8_t* volatile rgb = NULL;
JSAMPROW buffer[1];
int jpeg_row_stride;
jpeg_config_input.err = jpeg_std_error(&jerr);
jpeg_config_input.dct_method = JDCT_IFAST;
jpeg_config_input.do_fancy_upsampling = FALSE;
jpeg_config_input.two_pass_quantize = FALSE;
jpeg_config_input.dither_mode = JDITHER_ORDERED;
jpeg_create_decompress(&jpeg_config_input);
jpeg_stdio_src(&jpeg_config_input, input);
DEBUG("after constructor decompress");
if(jpeg_read_header(&jpeg_config_input, TRUE) != JPEG_HEADER_OK) {
jpeg_destroy_decompress(&jpeg_config_input);
return 1;
}
DEBUG("after header read");
jpeg_config_input.dct_method = JDCT_IFAST;
jpeg_config_input.do_fancy_upsampling = FALSE;
jpeg_config_input.two_pass_quantize = FALSE;
jpeg_config_input.dither_mode = JDITHER_ORDERED;
jpeg_calc_output_dimensions(&jpeg_config_input);
DEBUG("start decompress");
if(jpeg_start_decompress(&jpeg_config_input) == FALSE) {
jpeg_destroy_decompress(&jpeg_config_input);
return 1;
}
DEBUG("hot");
jpeg_row_stride = jpeg_config_input.output_width * jpeg_config_input.output_components;
rgb = (u_int8_t*)malloc(jpeg_config_input.output_height * jpeg_row_stride);
buffer[0] = (JSAMPLE*)rgb;
while (jpeg_config_input.output_scanline < jpeg_config_input.output_height) {
jpeg_read_scanlines(&jpeg_config_input, buffer, 1);
buffer[0] += jpeg_row_stride;
}
DEBUG("end decompress");
jpeg_finish_decompress(&jpeg_config_input);
jpeg_destroy_decompress(&jpeg_config_input);
DEBUG("finish decompress");
////////////////////////////////////////////////////////////////
// ENCODE
// resize: https://chromium.googlesource.com/webm/libwebp/+/0.2.0/examples/cwebp.c#1174
WebPPicture picture;
if (!WebPPictureInit(&picture)) {
DEBUG("ERR picture init");
return 1;
}
picture.width = jpeg_config_input.output_width;
picture.height = jpeg_config_input.output_height;
if(!WebPPictureAlloc(&picture)) {
DEBUG("ALLOC ERR");
return 1;
}
WebPPictureImportRGB(&picture, rgb, jpeg_row_stride);
WebPConfig webp_config_output;
picture.writer = MyWriter;
picture.custom_ptr = output;
if (!WebPConfigInit(&webp_config_output)) {
DEBUG("ERR config init");
return 1;
}
webp_config_output.image_hint = WEBP_HINT_PHOTO;
webp_config_output.method = 0;
if (!WebPValidateConfig(&webp_config_output)) {
DEBUG("ERR WEB VALIDATION");
}
fprintf(stderr, "rescale start %F\n", ((double)clock() - t)/CLOCKS_PER_SEC * 1000);
if (!WebPPictureRescale(&picture, jpeg_config_input.output_width / 4, jpeg_config_input.output_height / 4)) {
DEBUG("ERR Rescale");
}
DEBUG("encoder start");
WebPEncode(&webp_config_output, &picture);
DEBUG("encoder done");
WebPPictureFree(&picture);
DEBUG("everything is free");
}
*/
void jpeg_size(FILE* infile, int* height, int* width) {
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
*width = cinfo.image_width;
*height = cinfo.image_height;
jpeg_destroy_decompress(&cinfo);
}

View file

@ -1,10 +0,0 @@
#include <stdio.h>
#include "jpeglib.h"
#include "utils.h"
void jpeg_size(FILE* infile, int* height, int* width);
int jpeg_to_jpeg(FILE* input, FILE* output, int targetSize);
int jpeg_to_webp(FILE* input, FILE* output, int targetSize);

View file

@ -1,142 +0,0 @@
#include <string.h>
#include <png.h>
#include "webp/encode.h"
#include "utils.h"
static int MyWriter(const uint8_t* data, size_t data_size, const WebPPicture* const pic) {
FILE* const out = (FILE*)pic->custom_ptr;
return data_size ? (fwrite(data, data_size, 1, out) == 1) : 1;
}
int png_to_webp(FILE* input, FILE* output, int targetSize) {
WebPPicture picture;
#ifdef HAS_DEBUG
clock_t t;
t = clock();
#endif
png_image image;
memset(&image, 0, sizeof image);
image.version = PNG_IMAGE_VERSION;
DEBUG("reading png");
if (!png_image_begin_read_from_stdio(&image, input)) {
ERROR("png_image_begin_read_from_stdio");
return 1;
}
DEBUG("allocate");
png_bytep buffer;
image.format = PNG_FORMAT_RGBA;
buffer = malloc(PNG_IMAGE_SIZE(image));
if (buffer == NULL) {
ERROR("png_malloc");
png_image_free(&image);
return 1;
}
DEBUG("start reading");
if (!png_image_finish_read(&image, NULL, buffer, 0, NULL)) {
ERROR("png_image_finish_read");
png_image_free(&image);
free(buffer);
return 1;
}
/////////////////////////////////////////////
// encode to webp
DEBUG("start encoding");
if (!WebPPictureInit(&picture)) {
ERROR("WebPPictureInit");
png_image_free(&image);
free(buffer);
return 1;
}
picture.width = image.width;
picture.height = image.height;
if(!WebPPictureAlloc(&picture)) {
ERROR("WebPPictureAlloc");
png_image_free(&image);
free(buffer);
return 1;
}
DEBUG("start encoding import");
WebPPictureImportRGBA(&picture, buffer, PNG_IMAGE_ROW_STRIDE(image));
png_image_free(&image);
free(buffer);
WebPConfig webp_config_output;
picture.writer = MyWriter;
picture.custom_ptr = output;
DEBUG("start encoding config init");
if (!WebPConfigInit(&webp_config_output)) {
ERROR("ERR config init");
WebPPictureFree(&picture);
return 1;
}
webp_config_output.method = 0;
webp_config_output.quality = 30;
if (!WebPValidateConfig(&webp_config_output)) {
ERROR("ERR WEB VALIDATION");
WebPPictureFree(&picture);
return 1;
}
DEBUG("rescale start");
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");
WebPPictureFree(&picture);
return 1;
}
}
DEBUG("encoder start");
WebPEncode(&webp_config_output, &picture);
DEBUG("encoder done");
WebPPictureFree(&picture);
DEBUG("cleaning up");
return 0;
}
int png_to_png(FILE* input, FILE* output, int targetSize) {
#ifdef HAS_DEBUG
clock_t t;
t = clock();
#endif
png_image image;
memset(&image, 0, sizeof image);
image.version = PNG_IMAGE_VERSION;
DEBUG("> reading png");
if (!png_image_begin_read_from_stdio(&image, input)) {
DEBUG("png_image_begin_read_from_stdio");
return 1;
}
DEBUG("> allocate");
png_bytep buffer;
image.format = PNG_FORMAT_RGBA;
buffer = malloc(PNG_IMAGE_SIZE(image));
if (buffer == NULL) {
DEBUG("png_malloc");
png_image_free(&image);
return 1;
}
DEBUG("> start reading");
if (!png_image_finish_read(&image, NULL, buffer, 0, NULL)) {
DEBUG("png_image_finish_read");
png_image_free(&image);
free(buffer);
return 1;
}
DEBUG("> write");
if (!png_image_write_to_stdio(&image, output, 0, buffer, 0, NULL)) {
DEBUG("png_image_write_to_stdio");
png_image_free(&image);
free(buffer);
return 1;
}
DEBUG("> end");
png_image_free(&image);
free(buffer);
return 0;
}

View file

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

View file

@ -1,82 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <libraw/libraw.h>
#include "utils.h"
#include "image_jpeg.h"
#define BUF_SIZE 1024 * 1024
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) {
ERROR("mkstemp_in");
return 1;
}
FILE* f_in = fdopen(_mkstemp_in, "w");
if (f_in == NULL) {
remove(fname_in);
return 1;
}
char content[BUF_SIZE];
int read;
while ((read = fread(content, sizeof(char), BUF_SIZE, input))) {
fwrite(content, read, sizeof(char), f_in);
}
DEBUG("libraw init");
libraw_data_t *raw = libraw_init(0);
DEBUG("libraw open file");
if (libraw_open_file(raw, fname_in) != 0) {
ERROR("libraw_open_file");
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";
int _mkstemp_out = mkstemp(fname_out);
if (_mkstemp_out == -1) {
ERROR("mkstemp_out");
remove(fname_in);
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, targetSize);
fclose(f_out);
fclose(f_in);
remove(fname_in);
remove(fname_out);
DEBUG("process complete");
return err;
}
}
ERROR("not implemented - abort");
// if (libraw_unpack(raw) != 0) DEBUG("HERE0");
// if (libraw_dcraw_process(raw) != 0) DEBUG("HERE1");
// if (libraw_dcraw_ppm_tiff_writer(raw, fname_out) != 0) DEBUG("HERE2");
// if (libraw_dcraw_thumb_writer(raw, fname_out) != 0) DEBUG("HERE3");
// DEBUG("HERE__");
fclose(f_in);
remove(fname_in);
remove(fname_out);
libraw_close(raw);
return 1;
}

View file

@ -1,7 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <libraw/libraw.h>
#include "utils.h"
#include "image_jpeg.h"
int raw_to_jpeg(FILE* input, FILE* output, int targetSize);

View file

@ -1,27 +0,0 @@
#include <stdio.h>
#include "webp/decode.h"
#define DEFAULT_SIZE 100
#define STEP_SIZE 100
void webp_size(FILE* infile, int* height, int* width) {
uint8_t *buffer[DEFAULT_SIZE];
size_t buffer_sz=DEFAULT_SIZE;
size_t i=0;
while (!feof(infile)) {
// buffer[i] = fgetc(infile);
fread(buffer, buffer_sz+1, sizeof(char), infile);
i++;
if (i >= buffer_sz) {
buffer_sz += STEP_SIZE;
void *tmp = buffer;
buffer = realloc(buffer, buffer_sz);
if (buffer == NULL) {
free(tmp);
break;
}
}
}
// WebPGetInfo(buffer, buffer_sz, height, width);
}

View file

@ -1,3 +0,0 @@
#include <stdio.h>
void webp_size(FILE* infile, int* height, int* width);

View file

@ -1,5 +0,0 @@
#include <stdio.h>
#include "jpeglib.h"
#include "utils.h"
#define JPEG_QUALITY 50

View file

@ -1,6 +0,0 @@
#include <stdio.h>
#include "image_jpeg.h"
int main(int argc, char **argv) {
return jpeg_to_jpeg(stdin, stdout, 200);
}

View file

@ -1,6 +0,0 @@
#include <stdio.h>
#include "image_png.h"
int main(int argc, char **argv) {
return png_to_webp(stdin, stdout, 200);
}

View file

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

View file

@ -1,13 +0,0 @@
#include <string.h>
#include <png.h>
#include "webp/encode.h"
#include "utils.h"
static int MyWriter(const uint8_t* data, size_t data_size, const WebPPicture* const pic) {
FILE* const out = (FILE*)pic->custom_ptr;
return data_size ? (fwrite(data, data_size, 1, out) == 1) : 1;
}
int png_to_webp(FILE* input, FILE* output) {
}

View file

@ -1,132 +0,0 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <dirent.h>
#include "utils.h"
#include "jpeg_to_jpeg.h"
#include "png_to_webp.h"
#include "jpeg.h"
// #include "webp.h"
int strEndsWith(const char *s, const char *suff) {
size_t slen = strlen(s);
size_t sufflen = strlen(suff);
return slen >= sufflen && !memcmp(s + slen - sufflen, suff, sufflen);
}
void test_jpeg_to_jpeg(const char* basefolder) {
struct dirent *de;
DIR *dp;
int n = 0;
clock_t t = clock();
DEBUG("==================");
DEBUG("TEST: jpeg_to_jpeg");
dp = opendir(basefolder);
assert(dp != NULL);
remove("/tmp/out.dat");
while ((de = readdir (dp)) != NULL) {
if (strEndsWith(de->d_name, ".jpeg") == 0 && strEndsWith(de->d_name, ".jpg") == 0) {
continue;
}
// STEP1: setup the test
n += 1;
char input_fname[2048] = "";
strcpy(input_fname, basefolder);
strcat(input_fname, de->d_name);
fprintf(stderr, "= Processing[%s]:\n", input_fname);
FILE* input = fopen(input_fname, "r");
FILE* output = fopen("/tmp/out.dat", "w");
// STEP2: run the test
int ret = jpeg_to_jpeg(input, output);
fclose(input);
fclose(output);
// STEP3: assertions
int width = -1;
int height = -1;
output = fopen("/tmp/out.dat", "r");
jpeg_size(output, &width, &height);
fclose(output);
if (width < 0 || width > 800) {
fprintf(stderr, "%dx%d", width, height);
assert("width outside range" == NULL);
}
if (height < 0 || height > 800) {
fprintf(stderr, "height[%d]", height);
assert("height outside range" == NULL);
}
assert(ret == 0);
remove("/tmp/out.dat");
}
assert(n > 0);
closedir(dp);
}
void test_png_to_webp(const char* basefolder) {
struct dirent *de;
DIR *dp;
int n = 0;
clock_t t = clock();
DEBUG("==================");
DEBUG("TEST: png_to_webp");
dp = opendir(basefolder);
assert(dp != NULL);
remove("/tmp/out.dat");
while ((de = readdir (dp)) != NULL) {
if (strEndsWith(de->d_name, ".png") == 0) {
continue;
}
// STEP1: setup the test
n += 1;
char input_fname[2048] = "";
strcpy(input_fname, basefolder);
strcat(input_fname, de->d_name);
fprintf(stderr, "= Processing[%s]:\n", input_fname);
FILE* input = fopen(input_fname, "r");
FILE* output = fopen("/tmp/out.dat", "w");
// STEP2: run the test
int ret = png_to_webp(input, output);
fclose(input);
fclose(output);
// STEP3: assertions
int width = -1;
int height = -1;
output = fopen("/tmp/out.dat", "r");
// webp_size(output, &width, &height);
fclose(output);
if (width < 0 || width > 800) {
fprintf(stderr, "%dx%d", width, height);
assert("width outside range" == NULL);
}
if (height < 0 || height > 800) {
fprintf(stderr, "height[%d]", height);
assert("height outside range" == NULL);
}
assert(ret == 0);
remove("/tmp/out.dat");
}
assert(n > 0);
closedir(dp);
}
void test_raw_to_jpeg(const char* basename) {
clock_t t = clock();
DEBUG("==================");
DEBUG("(TODO)TEST: raw_to_jpeg");
}
int main(int args, const char **argv) {
if (args != 2) {
ERROR("need path with pictures in argument");
return 1;
}
// test_jpeg_to_jpeg(argv[1]);
// test_png_to_webp(argv[1]);
// test_raw_to_jpeg(argv[1]);
}

View file

@ -1,12 +0,0 @@
#define HAS_DEBUG 1
#if HAS_DEBUG == 1
#include <time.h>
#include <stdlib.h>
#define DEBUG(r) (fprintf(stderr, "[DEBUG::('" r "')(%.2Fms)]", ((double)clock() - t)/CLOCKS_PER_SEC * 1000))
#else
#define DEBUG(r) ((void)0)
#endif
#define ERROR(r) (fprintf(stderr, "[ERROR:('" r "')]"))
#define min(a, b) (a > b ? b : a)