Lymphatus / libcaesium

The Caesium compression library written in Rust (with a C interface)
Apache License 2.0
128 stars 23 forks source link

png image processing takes a long time #22

Closed seamory closed 1 month ago

seamory commented 1 month ago

Compress a png file, after the width and height parameters are passed in, the processing takes a long time. I'm pretty sure I added the --release parameter at compile time and didn't use the zopfli algorithm.

Following ara my codes:

package main

import (
    "image-compression/pkg/libcaesium"
    "log"
    "time"
)

func main() {
    log.Println(time.Now())
    params := libcaesium.NewCCSParameters()
    params.SetKeepMatedata(true)
    params.SetJpegQuality(80)
    //params.SetJpegChromaSubsampling(0)
    params.SetPngQuality(80)
    params.SetPngOptimizationLevel(3)
    params.SetPngForceZopfli(false)
    params.SetGifQuality(80)
    params.SetWebpQuality(80)
    //params.SetTiffCompression(80)
    //params.SetTiffDeflateLevel(3)
    params.SetOptimize(false)
    params.SetWidth(1512) // It is 0.5 times the width of IMG_1204.png
    params.SetHeight(2016) // It is 0.5 times the height of IMG_1204.png
    r := libcaesium.CCompress(
        "D:\\Home\\Default\\Pictures\\IMG_1204.png",
        "D:\\Home\\Default\\Pictures\\IMG_1204_output.png",
        params,
        //params,
        //uint64(1*1000*1000),
        //true,
        //libcaesium.Jpeg,
        //params,
    )
    defer func() {
        libcaesium.DeleteCCSParameters(params)
        libcaesium.DeleteCCSResult(r)
    }()
    log.Println(r.GetSuccess(), r.GetErrorMessage())
    log.Println(time.Now())
}

Terminate output image

seamory commented 1 month ago

By the way, if both width and height are specified, the compression rate of the output PNG may even be worse than when they are not specified.

Lymphatus commented 1 month ago

I tested on a fairly large PNG (4032x3024 - 10.4 Mb) and with the same options as yours. Compiled with --release it takes less than 1 second to complete, while a non-optimized compilation takes around 25 seconds. I'm not familiar with the language you are using (seems Go to me), but there might be some issue while passing parameters to the library. Can you give me more details on that?

Passing width a height takes more time because the image is resized first, then goes trough the compression process.

seamory commented 1 month ago

@Lymphatus I used swig to convert the libcaesium.h I wrote into go. Call through caesium's dynamic library. I tested it again and found that when I only set the height, I could get an image with the same output width as the set height, and it ran very fast. If I just set the width, then the width and height of the output image are the same as the input image.

libcaesium.h

#ifndef CCS_COMPRESS_H
#define CCS_COMPRESS_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>

typedef enum SupportedFileTypes {
    Jpeg = 0,
    Png = 1,
    Gif = 2,
    WebP = 3,
    Tiff = 4,
    Unkn = 5
} SupportedFileTypes;

typedef struct CCSResult {
    bool success;
    char *error_message;
} CCSResult;

typedef struct CCSParameters {
    bool keep_matedata;
    uint32_t jpeg_quality;
    uint32_t jpeg_chroma_subsampling; // support 444, 422, 420, 411
    uint32_t  png_quality;
    uint32_t  png_optimization_level;
    bool  png_force_zopfli;
    uint32_t  gif_quality;
    uint32_t  webp_quality;
    uint32_t  tiff_compression; // support 1:Lzw 2:Deflate 3:Packbits Other Int:Uncompressed
    uint32_t  tiff_deflate_level; // support 1:Fast 6:Balanced Other Int:Best
    bool  optimize;
    uint32_t  width;
    uint32_t  height;
} CCSParameters;

CCSResult c_compress(const char* input_path, const char* output_path, CCSParameters* params);

CCSResult c_compress_to_size(const char* input_path, const char* output_path, CCSParameters* params, uint64_t max_output_size, bool return_smallest);

CCSResult c_convert(const char* input_path, const char* output_path, SupportedFileTypes format, CCSParameters* params);

#ifdef __cplusplus
}
#endif

#endif
seamory commented 1 month ago

@Lymphatus I think I found the problem, CCSParameters in the c header file definition I referenced ReadMe from the project. but just now, I added printing against width and height in c_set_parameters in src/interface.rs and found that the structure didn't seem to be aligned. So I compared the CCSParameters definition in src/interface.rs again and found that a jpeg_progressive field was added. Now the problem is solved. Thanks a lot! Maybe it's time for ReadMe to be updated! :)

Lymphatus commented 1 month ago

You're totally right. I added that option recently and forgot to update the README. My bad, I'm fixing it right away.