mirror of
				https://github.com/mickael-kerjean/filestash.git
				synced 2025-10-31 10:07:15 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			107 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <webp/decode.h>
 | |
| #include <webp/encode.h>
 | |
| #include "utils.h"
 | |
| 
 | |
| #define WEBP_QUALITY 75
 | |
| #define INITIAL_BUFFER_SIZE 1024*64 // 128kB
 | |
| #define MAX_BUFFER_SIZE 1024*1024*2 // 2MB
 | |
| 
 | |
| int webp_to_webp(int inputDesc, int outputDesc, int targetSize) {
 | |
| #ifdef HAS_DEBUG
 | |
|   clock_t t;
 | |
|   t = clock();
 | |
| #endif
 | |
|   if (targetSize < 0) {
 | |
|     targetSize = -targetSize;
 | |
|   }
 | |
|   int status = 0;
 | |
|   FILE* input = fdopen(inputDesc, "rb");
 | |
|   FILE* output = fdopen(outputDesc, "wb");
 | |
|   if (!input || !output) {
 | |
|     ERROR("setup");
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   // STEP1: setup everything
 | |
|   size_t data_size = 0;
 | |
|   size_t buffer_size = INITIAL_BUFFER_SIZE;
 | |
|   uint8_t* data = (uint8_t*)malloc(buffer_size);
 | |
|   if (!data) {
 | |
|     ERROR("malloc");
 | |
|     return 1;
 | |
|   }
 | |
|   size_t bytes_read;
 | |
|   while ((bytes_read = fread(data + data_size, 1, buffer_size - data_size, input)) > 0) {
 | |
|     data_size += bytes_read;
 | |
|     if (buffer_size - data_size == 0) {
 | |
|       DEBUG("realloc");
 | |
|       if (buffer_size >= MAX_BUFFER_SIZE) {
 | |
|         free(data);
 | |
|         ERROR("abort");
 | |
|         return 1;
 | |
|       }
 | |
|       buffer_size *= 2;
 | |
|       if (buffer_size > MAX_BUFFER_SIZE) buffer_size = MAX_BUFFER_SIZE;
 | |
|       uint8_t* new_data = (uint8_t*)realloc(data, buffer_size);
 | |
|       if (!new_data) {
 | |
|         free(data);
 | |
|         ERROR("realloc");
 | |
|         return 1;
 | |
|       }
 | |
|       data = new_data;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // STEP2: decode
 | |
|   int width, height, scale_factor;
 | |
|   if (!WebPGetInfo(data, data_size, &width, &height)) {
 | |
|     free(data);
 | |
|     ERROR("init");
 | |
|     return 1;
 | |
|   }
 | |
|   DEBUG("init");
 | |
|   WebPDecoderConfig config;
 | |
|   if (!WebPInitDecoderConfig(&config)) {
 | |
|     free(data);
 | |
|     ERROR("config");
 | |
|     return 1;
 | |
|   }
 | |
|   scale_factor = (height > targetSize) ? height / targetSize : 1;
 | |
|   config.options.use_scaling = 1;
 | |
|   config.options.scaled_width = width / scale_factor;
 | |
|   config.options.scaled_height = height / scale_factor;
 | |
|   config.output.colorspace = MODE_rgbA;
 | |
|   DEBUG("config");
 | |
|   if (WebPDecode(data, data_size, &config) != VP8_STATUS_OK) {
 | |
|     WebPFreeDecBuffer(&config.output);
 | |
|     free(data);
 | |
|     ERROR("decode");
 | |
|     return 1;
 | |
|   }
 | |
|   free(data);
 | |
|   DEBUG("decode");
 | |
| 
 | |
|   // STEP3: encode
 | |
|   size_t output_size = 0;
 | |
|   uint8_t* output_data = NULL;
 | |
|   output_size = WebPEncodeRGBA(
 | |
|       config.output.u.RGBA.rgba, config.options.scaled_width,
 | |
|       config.options.scaled_height, config.output.u.RGBA.stride,
 | |
|       WEBP_QUALITY, &output_data
 | |
|   );
 | |
|   if (output_data == NULL) {
 | |
|     WebPFreeDecBuffer(&config.output);
 | |
|     ERROR("encode");
 | |
|     return 1;
 | |
|   }
 | |
|   DEBUG("encode");
 | |
|   fwrite(output_data, output_size, 1, output);
 | |
|   fflush(output);
 | |
|   WebPFree(output_data);
 | |
|   WebPFreeDecBuffer(&config.output);
 | |
|   DEBUG("done");
 | |
|   return status;
 | |
| }
 | 
