video2gif 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a792d0bc3ded611a4295f7195ab17fbe5a71c65ae84bc527eb02c9f6c667088c
4
- data.tar.gz: f17cfefa5ef240925a2915ae089df6c7d9eacd7bf2d1ac449bce6f707a2a15c7
3
+ metadata.gz: 9033455c4d54099067dd61428f3190e75bc52783ab0ee110effa5cb9efedf688
4
+ data.tar.gz: fd1092a4ef5ffa4c280861fa084444ed2d3b260139062488824c71c3de0957ee
5
5
  SHA512:
6
- metadata.gz: ba5e69371e4edb486ff79a7ffa539cbf656c3edf1bc1794f58a02add3240fd81acadaaba8502b123990e09efa1d630560b4a20357d747f3349b3f9314864a9aa
7
- data.tar.gz: 243ddc56a97b5470d7771e90731dafbb9d0c69c2427e406a4f6f664305fe6d1bd40b27cf29b8a99221dabcce6d76a562ea5321767e161cdf72be165a2a2f94a3
6
+ metadata.gz: 19a4bfdfb4abd9f13c9c0b8f6a558ef9c1563c620c864e70b3ed96f59b2dd344e153c7900561b92298b18fdc3094ea8a8feb7f4fc2d1f67b2ba90adbc95f757a
7
+ data.tar.gz: f7c4f43908ca23a75651a73c3cff2cd30407024296ad3fab227f6dba331d0276228e54032458cf7d80739c0b6b4bd8f440508ef101ce5d6edd788e9f0d680084
data/README.md CHANGED
@@ -3,10 +3,10 @@ video2gif
3
3
 
4
4
  `video2gif` eases converting any video into a GIF.
5
5
 
6
- It uses [FFMpeg] and optionally [ImageMagick], so it understands any
7
- video that [FFMpeg] does. It has an array of options to allow you to
8
- select the part of the video you want, crop it automatically, overlay
9
- text, and manipulate the color and brightness.
6
+ It uses [FFMpeg], so it understands any video that [FFMpeg] does. It has
7
+ an array of options to allow you to select the part of the video you
8
+ want, crop it automatically, overlay text, and manipulate the color and
9
+ brightness.
10
10
 
11
11
 
12
12
  Installation
@@ -17,9 +17,6 @@ available in the system `$PATH`. If you can run `ffmpeg` from the
17
17
  command line, you're probably good. If not, use your favorite package
18
18
  manager to install it.
19
19
 
20
- If you install [ImageMagick], further optimization will automatically
21
- take place on the resulting GIF.
22
-
23
20
  Note that some features may not be available by default. For example,
24
21
  tonemapping (used for HDR videos) requires `libzimg` support, not
25
22
  included by default in the [FFMpeg] supplied by [Homebrew].
data/lib/video2gif.rb CHANGED
@@ -93,12 +93,6 @@ module Video2gif
93
93
  options[:cropdetect] = c || 24
94
94
  end
95
95
 
96
- parser.on('-o',
97
- '--[no-]optimize',
98
- 'Attempt to optimize GIF size with ImageMagick (default yes if available)') do |o|
99
- options[:optimize] = o
100
- end
101
-
102
96
  parser.on('--contrast CONTRAST',
103
97
  'Apply contrast adjustment, scaled from -2.0 to 2.0 (default 1)') do |c|
104
98
  options[:contrast] = c
@@ -239,19 +233,13 @@ module Video2gif
239
233
  exit
240
234
  end
241
235
 
242
- if !is_executable?('convert') && options[:optimize]
243
- logger.warn('ImageMagick isn\'t available! Optimization will be'\
244
- ' disabled!') unless options[:quiet]
245
- options[:optimize] = false
246
- end
247
-
248
236
  options
249
237
  end
250
238
 
251
239
  def self.build_filter_complex(options)
252
- fps = options[:fps] || 15
253
- palette_size = options[:palette] || 256
254
- width = options[:width] # default is not to scale at all
240
+ fps = options[:fps] || 15
241
+ max_colors = options[:palette] ? "max_colors=#{options[:palette]}:" : ''
242
+ width = options[:width] # default is not to scale at all
255
243
 
256
244
  # create filter elements
257
245
  fps_filter = "fps=#{fps}"
@@ -275,17 +263,17 @@ module Video2gif
275
263
  end
276
264
  eq_filter = if options[:eq]
277
265
  'eq=' + %W[
278
- contrast=#{options[:contrast] || 1}
279
- brightness=#{options[:brightness] || 0}
280
- saturation=#{options[:saturation] || 1}
281
- gamma=#{options[:gamma] || 1}
282
- gamma_r=#{options[:gamma_r] || 1}
283
- gamma_g=#{options[:gamma_g] || 1}
284
- gamma_b=#{options[:gamma_b] || 1}
266
+ contrast=#{ options[:contrast] || 1 }
267
+ brightness=#{ options[:brightness] || 0 }
268
+ saturation=#{ options[:saturation] || 1 }
269
+ gamma=#{ options[:gamma] || 1 }
270
+ gamma_r=#{ options[:gamma_r] || 1 }
271
+ gamma_g=#{ options[:gamma_g] || 1 }
272
+ gamma_b=#{ options[:gamma_b] || 1 }
285
273
  ].join(':')
286
274
  end
287
- palettegen_filter = "palettegen=max_colors=#{palette_size}:stats_mode=diff"
288
- paletteuse_filter = 'paletteuse=dither=sierra2_4a:diff_mode=rectangle'
275
+ palettegen_filter = "palettegen=#{max_colors}stats_mode=diff"
276
+ paletteuse_filter = 'paletteuse=dither=floyd_steinberg:diff_mode=rectangle'
289
277
  drawtext_filter = if options[:text]
290
278
  count_of_lines = options[:text].scan(/\\n/).count + 1
291
279
 
@@ -321,10 +309,10 @@ module Video2gif
321
309
  # before applying the palettegen so that we accurately predict the
322
310
  # final palette
323
311
  filter_complex << fps_filter
324
- filter_complex << crop_filter if crop_filter
325
- filter_complex << scale_filter if options[:width] unless options[:tonemap]
312
+ filter_complex << crop_filter if crop_filter
313
+ filter_complex << scale_filter if options[:width] unless options[:tonemap]
326
314
  filter_complex << tonemap_filters if options[:tonemap]
327
- filter_complex << eq_filter if options[:eq]
315
+ filter_complex << eq_filter if options[:eq]
328
316
  filter_complex << drawtext_filter if options[:text]
329
317
 
330
318
  # then generate the palette (and label this filter stream)
@@ -336,10 +324,10 @@ module Video2gif
336
324
  # affected by scaling)
337
325
  filter_complex << '[0:v][palette]' + paletteuse_filter
338
326
  filter_complex << fps_filter
339
- filter_complex << crop_filter if crop_filter
340
- filter_complex << scale_filter if options[:width] unless options[:tonemap]
327
+ filter_complex << crop_filter if crop_filter
328
+ filter_complex << scale_filter if options[:width] unless options[:tonemap]
341
329
  filter_complex << tonemap_filters if options[:tonemap]
342
- filter_complex << eq_filter if options[:eq]
330
+ filter_complex << eq_filter if options[:eq]
343
331
  filter_complex << drawtext_filter if options[:text]
344
332
 
345
333
  filter_complex.join(',')
@@ -349,51 +337,38 @@ module Video2gif
349
337
  if args[1]
350
338
  args[1].end_with?('.gif') ? args[1] : args[1] + '.gif'
351
339
  else
352
- File.join(File.dirname(args[0]),
353
- File.basename(args[0], '.*') + '.gif')
340
+ File.join(File.dirname(args[0]), File.basename(args[0], '.*') + '.gif')
354
341
  end
355
342
  end
356
343
 
357
- def self.build_ffmpeg_gif_command(args, options, logger)
358
- command = []
359
- command << 'ffmpeg'
360
- command << '-y' # always overwrite
344
+ def self.build_ffmpeg_cropdetect_command(args, options, logger)
345
+ command = ['ffmpeg']
361
346
  command << '-analyzeduration' << '2147483647' << '-probesize' << '2147483647'
362
347
  command << '-nostdin'
363
348
  command << '-ss' << options[:seek] if options[:seek]
364
349
  command << '-t' << options[:time] if options[:time]
365
350
  command << '-i' << args[0]
366
- command << '-filter_complex' << build_filter_complex(options)
367
- command << '-f' << 'gif'
368
-
369
- # if we're not optimizing, we won't send to stdout
370
- command << (options[:optimize] ? '-' : build_output_filename(args))
371
-
372
- logger.info(command.join(' ')) if options[:verbose] unless options[:quiet]
373
-
374
- command
375
- end
376
-
377
- def self.build_convert_optimize_command(args, options, logger)
378
- command = []
379
- command << 'convert' << '-' << '-layers' << 'Optimize' << build_output_filename(args)
351
+ command << '-filter_complex' << "cropdetect=limit=#{options[:cropdetect]}"
352
+ command << '-f' << 'null'
353
+ command << '-'
380
354
 
381
355
  logger.info(command.join(' ')) if options[:verbose] unless options[:quiet]
382
356
 
383
357
  command
384
358
  end
385
359
 
386
- def self.build_ffmpeg_cropdetect_command(args, options, logger)
387
- command = []
388
- command << 'ffmpeg'
360
+ def self.build_ffmpeg_gif_command(args, options, logger)
361
+ command = ['ffmpeg']
362
+ command << '-y' # always overwrite
389
363
  command << '-analyzeduration' << '2147483647' << '-probesize' << '2147483647'
390
364
  command << '-nostdin'
391
365
  command << '-ss' << options[:seek] if options[:seek]
392
366
  command << '-t' << options[:time] if options[:time]
393
367
  command << '-i' << args[0]
394
- command << '-filter_complex' << "cropdetect=limit=#{options[:cropdetect]}"
395
- command << '-f' << 'null'
396
- command << '-'
368
+ command << '-filter_complex' << build_filter_complex(options)
369
+ command << '-gifflags' << '+transdiff' # enabled by default
370
+ command << '-f' << 'gif'
371
+ command << build_output_filename(args)
397
372
 
398
373
  logger.info(command.join(' ')) if options[:verbose] unless options[:quiet]
399
374
 
@@ -405,7 +380,7 @@ module Video2gif
405
380
  options = parse_args(ARGV, logger)
406
381
 
407
382
  if options[:cropdetect]
408
- Open3.popen3(*build_ffmpeg_cropdetect_command(ARGV, options, logger)) do |stdin, stdout, stderr, wait_thr|
383
+ Open3.popen3(*build_ffmpeg_cropdetect_command(ARGV, options, logger)) do |stdin, stdout, stderr, thread|
409
384
  stdin.close
410
385
  stdout.close
411
386
  stderr.each(chomp: true) do |line|
@@ -414,26 +389,19 @@ module Video2gif
414
389
  end
415
390
  stderr.close
416
391
 
417
- raise "Process #{wait_thr.pid} failed! Try again with --verbose to see error." unless wait_thr.value.success?
392
+ raise "Process #{thread.pid} failed! Try again with --verbose to see error." unless thread.value.success?
418
393
  end
419
394
  end
420
395
 
421
- gif_pipeline_items = [build_ffmpeg_gif_command(ARGV, options, logger)]
422
- gif_pipeline_items << build_convert_optimize_command(ARGV, options, logger) if options[:optimize]
423
-
424
- read_io, write_io = IO.pipe
425
- Open3.pipeline_start(*gif_pipeline_items, out: write_io, err: write_io) do |threads|
426
- write_io.close
427
- if options[:verbose]
428
- read_io.each(chomp: true) { |line| logger.info(line) unless options[:quiet] }
429
- else
430
- read_io.read(1024) until read_io.eof?
396
+ Open3.popen3(*build_ffmpeg_gif_command(ARGV, options, logger)) do |stdin, stdout, stderr, thread|
397
+ stdin.close
398
+ stdout.close
399
+ stderr.each(chomp: true) do |line|
400
+ logger.info(line) if options[:verbose] unless options[:quiet]
431
401
  end
432
- read_io.close
402
+ stderr.close
433
403
 
434
- threads.each do |t|
435
- raise "Process #{t.pid} failed! Try again with --verbose to see error." unless t.value.success?
436
- end
404
+ raise "Process #{thread.pid} failed! Try again with --verbose to see error." unless thread.value.success?
437
405
  end
438
406
  end
439
407
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Video2gif
4
- VERSION = '0.0.1'
4
+ VERSION = '0.0.2'
5
5
  end
data/video2gif.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  # the 'allowed_push_host' to allow pushing to a single host or delete
18
18
  # this section to allow pushing to any host.
19
19
  if spec.respond_to?(:metadata)
20
- spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
20
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
21
21
  spec.metadata['homepage_uri'] = spec.homepage
22
22
  spec.metadata['source_code_uri'] = "https://github.com/emilyst/video2gif"
23
23
  # spec.metadata['changelog_uri'] = "https://github.com/emilyst/video2gif"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: video2gif
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emily St.
@@ -93,7 +93,7 @@ homepage: https://github.com/emilyst/video2gif
93
93
  licenses:
94
94
  - CC0
95
95
  metadata:
96
- allowed_push_host: https://rubygems.org/
96
+ allowed_push_host: https://rubygems.org
97
97
  homepage_uri: https://github.com/emilyst/video2gif
98
98
  source_code_uri: https://github.com/emilyst/video2gif
99
99
  post_install_message: