Module: ImagePack

Defined in:
lib/image_pack.rb,
lib/image_pack/errors.rb,
lib/image_pack/backend.rb,
lib/image_pack/version.rb,
lib/image_pack/configuration.rb,
ext/image_pack/image_pack.c

Defined Under Namespace

Modules: Backend Classes: CancelledError, Configuration, EncodeError, Error, InvalidArgumentError, InvalidImageError, LimitExceededError, OutOfMemoryError, QualityConstraintError, UnsupportedError

Constant Summary collapse

ALGOS =
%i[jpeg_turbo mozjpeg].freeze
EXECUTION_MODES =
%i[direct nogvl offload auto].freeze
DEFAULT_QUALITY =
82
VERSION =
"0.2.0"

Class Method Summary collapse

Class Method Details

.__compress_jpeg(input, input_kind, output, output_kind, algo, quality, min_ssim, mozjpeg_trellis, progressive, strip_metadata, execution, cancellable, has_scheduler) ⇒ Object



1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
# File 'ext/image_pack/image_pack.c', line 1492

static VALUE ip_compress_jpeg_entry(VALUE self, VALUE input, VALUE input_kind, VALUE output,
                                    VALUE output_kind, VALUE algo, VALUE quality, VALUE min_ssim,
                                    VALUE mozjpeg_trellis, VALUE progressive, VALUE strip_metadata,
                                    VALUE execution, VALUE cancellable, VALUE has_scheduler) {
    ip_context_t *ctx = ip_context_new();
    if (!ctx)
        rb_raise(rb_eImagePackOutOfMemoryError, "failed to allocate native context");

    ip_output_kind_t out_kind = ip_parse_output_kind(output_kind);
    ctx->algo = ip_parse_algo(algo);
    ctx->quality = NUM2INT(quality);
    ctx->selected_quality = ctx->quality;
    ip_validate_quality_or_raise(ctx);
    ctx->min_ssim = NUM2DBL(min_ssim);
    ctx->ssim_guard_enabled = ctx->min_ssim > 0.0;
    ip_validate_min_ssim_or_raise(ctx);
    ctx->mozjpeg_trellis_enabled = ip_bool_value(mozjpeg_trellis);
    ctx->progressive = ip_bool_value(progressive);
    ctx->strip_metadata = ip_bool_value(strip_metadata);
    ctx->requested_execution = ip_parse_execution(execution);
    ctx->cancellable_requested = ip_bool_value(cancellable);
    ctx->has_scheduler = ip_bool_value(has_scheduler);
    apply_configuration(self, ctx);

    if (!ip_prepare_input_bytes(ctx, input, ip_parse_input_kind(input_kind)) ||
        !ip_prepare_output_path(ctx, output, out_kind)) {
        VALUE exception = ip_status_to_exception(ctx->status);
        char message[512];
        snprintf(message, sizeof(message), "%s", ctx->error_message);
        ip_context_free(ctx);
        rb_raise(exception, "%s", message[0] ? message : "invalid JPEG input");
    }

    if (ctx->requested_execution == IP_EXEC_AUTO && ctx->input_size < ctx->direct_input_threshold &&
        !ip_inspect_jpeg_header(ctx)) {
        VALUE exception = ip_status_to_exception(ctx->status);
        char message[512];
        snprintf(message, sizeof(message), "%s", ctx->error_message);
        ip_context_free(ctx);
        rb_raise(exception, "%s", message[0] ? message : "invalid JPEG input");
    }

    ip_run_context(ctx);
    VALUE result = ip_finish_output(ctx, out_kind);
    ip_context_free(ctx);
    return result;
}

.__compress_pixels(buffer, width, height, channels, output, output_kind, algo, quality, progressive, execution, cancellable, has_scheduler) ⇒ Object



1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
# File 'ext/image_pack/image_pack.c', line 1540

static VALUE ip_compress_pixels_entry(VALUE self, VALUE buffer, VALUE width, VALUE height,
                                      VALUE channels, VALUE output, VALUE output_kind, VALUE algo,
                                      VALUE quality, VALUE progressive, VALUE execution,
                                      VALUE cancellable, VALUE has_scheduler) {
    ip_context_t *ctx = ip_context_new();
    if (!ctx)
        rb_raise(rb_eImagePackOutOfMemoryError, "failed to allocate native context");

    ip_output_kind_t out_kind = ip_parse_output_kind(output_kind);
    ctx->algo = ip_parse_algo(algo);
    ctx->quality = NUM2INT(quality);
    ip_validate_quality_or_raise(ctx);
    ctx->progressive = ip_bool_value(progressive);
    ctx->strip_metadata = 1;
    ctx->requested_execution = ip_parse_execution(execution);
    ctx->cancellable_requested = ip_bool_value(cancellable);
    ctx->has_scheduler = ip_bool_value(has_scheduler);
    apply_configuration(self, ctx);

    if (!ip_prepare_pixels(ctx, buffer, NUM2INT(width), NUM2INT(height), NUM2INT(channels)) ||
        !ip_prepare_output_path(ctx, output, out_kind)) {
        VALUE exception = ip_status_to_exception(ctx->status);
        char message[512];
        snprintf(message, sizeof(message), "%s", ctx->error_message);
        ip_context_free(ctx);
        rb_raise(exception, "%s", message[0] ? message : "invalid pixel input");
    }

    validate_limits_for_pixels(ctx);
    if (ctx->status != IP_OK) {
        VALUE exception = ip_status_to_exception(ctx->status);
        char message[512];
        snprintf(message, sizeof(message), "%s", ctx->error_message);
        ip_context_free(ctx);
        rb_raise(exception, "%s", message);
    }

    ip_run_context(ctx);
    VALUE result = ip_finish_output(ctx, out_kind);
    ip_context_free(ctx);
    return result;
}

.__inspect_image(input, input_kind) ⇒ Object



637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
# File 'ext/image_pack/image_pack.c', line 637

static VALUE ip_inspect_image_entry(VALUE self, VALUE input, VALUE input_kind) {
    (void)self;
    ip_context_t *ctx = ip_context_new();
    if (!ctx)
        rb_raise(rb_eImagePackOutOfMemoryError, "failed to allocate native context");

    if (!ip_prepare_input_bytes(ctx, input, ip_parse_input_kind(input_kind)) ||
        !ip_inspect_jpeg_header(ctx)) {
        VALUE exception = ip_status_to_exception(ctx->status);
        char message[512];
        snprintf(message, sizeof(message), "%s", ctx->error_message);
        ip_context_free(ctx);
        rb_raise(exception, "%s", message[0] ? message : "failed to inspect JPEG image");
    }

    VALUE hash = rb_hash_new();
    rb_hash_aset(hash, ID2SYM(rb_intern("format")), ID2SYM(rb_intern("jpeg")));
    rb_hash_aset(hash, ID2SYM(rb_intern("width")), INT2NUM(ctx->width));
    rb_hash_aset(hash, ID2SYM(rb_intern("height")), INT2NUM(ctx->height));
    rb_hash_aset(hash, ID2SYM(rb_intern("channels")), INT2NUM(ctx->channels));
    rb_hash_aset(hash, ID2SYM(rb_intern("bit_depth")), INT2NUM(ctx->bit_depth));
    rb_hash_aset(hash, ID2SYM(rb_intern("decoded_bytes")), SIZET2NUM(ctx->decoded_bytes));
    ip_context_free(ctx);
    return hash;
}

.compress(input, output: nil, algo: :jpeg_turbo, quality: nil, min_ssim: nil, mozjpeg_trellis: true, progressive: false, strip_metadata: true, execution: nil, cancellable: false) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/image_pack.rb', line 48

def compress(input,
             output: nil,
             algo: :jpeg_turbo,
             quality: nil,
             min_ssim: nil,
             mozjpeg_trellis: true,
             progressive: false,
             strip_metadata: true,
             execution: nil,
             cancellable: false)
  validate_algo!(algo)
  validate_min_ssim!(min_ssim)
  validate_mozjpeg_trellis!(mozjpeg_trellis)
  quality_was_given = !quality.nil?
  effective_quality = quality_was_given ? quality : DEFAULT_QUALITY
  effective_quality = 1 if min_ssim && !quality_was_given
  validate_quality!(effective_quality)
  execution ||= configuration.execution
  validate_execution!(execution)
  validate_cancellable!(algo, execution, cancellable)

  normalized_input_kind = input_kind!(input)
  normalized_output_kind = output_kind!(output)
  has_scheduler = fiber_scheduler_active?

  __compress_jpeg(input, normalized_input_kind,
                  output, normalized_output_kind,
                  algo, effective_quality.to_i,
                  min_ssim ? min_ssim.to_f : 0.0,
                  mozjpeg_trellis ? 1 : 0,
                  progressive ? 1 : 0,
                   ? 1 : 0,
                  execution,
                  cancellable ? 1 : 0,
                  has_scheduler ? 1 : 0)
end

.compress_pixels(buffer, width:, height:, channels:, output: nil, algo: :jpeg_turbo, quality: DEFAULT_QUALITY, progressive: false, execution: nil, cancellable: false) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/image_pack.rb', line 85

def compress_pixels(buffer,
                    width:,
                    height:,
                    channels:,
                    output: nil,
                    algo: :jpeg_turbo,
                    quality: DEFAULT_QUALITY,
                    progressive: false,
                    execution: nil,
                    cancellable: false)
  validate_algo!(algo)
  validate_quality!(quality)
  validate_dimensions!(width, height, channels)
  execution ||= configuration.execution
  validate_execution!(execution)
  validate_cancellable!(algo, execution, cancellable)

  normalized_output_kind = output_kind!(output)
  has_scheduler = fiber_scheduler_active?

  __compress_pixels(buffer,
                    width.to_i, height.to_i, channels.to_i,
                    output, normalized_output_kind,
                    algo, quality.to_i,
                    progressive ? 1 : 0,
                    execution,
                    cancellable ? 1 : 0,
                    has_scheduler ? 1 : 0)
end

.configurationObject



37
38
39
# File 'lib/image_pack.rb', line 37

def configuration
  @configuration ||= Configuration.new
end

.configure {|configuration| ... } ⇒ Object

Yields:



41
42
43
44
45
46
# File 'lib/image_pack.rb', line 41

def configure
  return configuration unless block_given?

  yield(configuration)
  configuration
end

.inspect_image(input) ⇒ Object



115
116
117
# File 'lib/image_pack.rb', line 115

def inspect_image(input)
  __inspect_image(input, input_kind!(input))
end