Add automatic APNG detection (#2237)
This commit is contained in:
70
app/logical/apng_inspector.rb
Normal file
70
app/logical/apng_inspector.rb
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
class APNGInspector
|
||||||
|
attr_reader :frames
|
||||||
|
|
||||||
|
PNG_MAGIC_NUMBER = ["89504E470D0A1A0A"].pack('H*')
|
||||||
|
|
||||||
|
def initialize(file_path)
|
||||||
|
@file_path = file_path
|
||||||
|
@corrupted = false
|
||||||
|
@animated = false
|
||||||
|
end
|
||||||
|
|
||||||
|
#Calls associated block for each PNG chunk
|
||||||
|
#parameters passed are |chunk_name, chunk_length, file_descriptor|
|
||||||
|
#returns true if file is read succesfully from start to IEND, false otherwise.
|
||||||
|
def each_chunk
|
||||||
|
iend_reached = false
|
||||||
|
File.open(@file_path, 'rb') do |file|
|
||||||
|
return false if file.read(8) != PNG_MAGIC_NUMBER
|
||||||
|
|
||||||
|
while chunkheader = file.read(8)
|
||||||
|
return false if chunkheader.to_s.length != 8
|
||||||
|
|
||||||
|
chunk_len, chunk_name = chunkheader.unpack("Na4")
|
||||||
|
current_pos = file.tell
|
||||||
|
yield chunk_name, chunk_len, file
|
||||||
|
if chunk_name == "IEND"
|
||||||
|
iend_reached = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
file.seek(current_pos+chunk_len+4, IO::SEEK_SET)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return iend_reached
|
||||||
|
end
|
||||||
|
|
||||||
|
def inspect!
|
||||||
|
actl_corrupted = false
|
||||||
|
|
||||||
|
read_success = each_chunk do |name, len, file|
|
||||||
|
if name == 'acTL'
|
||||||
|
if len != 8 then
|
||||||
|
actl_corrupted = true
|
||||||
|
else
|
||||||
|
framedata = file.read(4)
|
||||||
|
if framedata.to_s.length != 4
|
||||||
|
actl_corrupted = true
|
||||||
|
else
|
||||||
|
framecount = framedata.unpack("N")[0]
|
||||||
|
if framecount < 1
|
||||||
|
actl_corrupted = true
|
||||||
|
else
|
||||||
|
@animated = true
|
||||||
|
@frames = framecount
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@corrupted = !read_success || actl_corrupted
|
||||||
|
return !@corrupted
|
||||||
|
end
|
||||||
|
|
||||||
|
def corrupted?
|
||||||
|
@corrupted
|
||||||
|
end
|
||||||
|
|
||||||
|
def animated?
|
||||||
|
!@corrupted && @animated && @frames > 1
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -163,6 +163,16 @@ class Post < ActiveRecord::Base
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_animated_png?
|
||||||
|
if file_ext =~ /png/i
|
||||||
|
apng = APNGInspector.new(file_path)
|
||||||
|
apng.inspect!
|
||||||
|
return apng.animated?
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def is_flash?
|
def is_flash?
|
||||||
file_ext =~ /swf/i
|
file_ext =~ /swf/i
|
||||||
@@ -607,7 +617,7 @@ class Post < ActiveRecord::Base
|
|||||||
def add_automatic_tags(tags)
|
def add_automatic_tags(tags)
|
||||||
return tags if !Danbooru.config.enable_dimension_autotagging
|
return tags if !Danbooru.config.enable_dimension_autotagging
|
||||||
|
|
||||||
tags -= %w(incredibly_absurdres absurdres highres lowres huge_filesize animated_gif flash webm mp4)
|
tags -= %w(incredibly_absurdres absurdres highres lowres huge_filesize animated_gif animated_png flash webm mp4)
|
||||||
|
|
||||||
if has_dimensions?
|
if has_dimensions?
|
||||||
if image_width >= 10_000 || image_height >= 10_000
|
if image_width >= 10_000 || image_height >= 10_000
|
||||||
@@ -639,6 +649,10 @@ class Post < ActiveRecord::Base
|
|||||||
if is_animated_gif?
|
if is_animated_gif?
|
||||||
tags << "animated_gif"
|
tags << "animated_gif"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if is_animated_png?
|
||||||
|
tags << "animated_png"
|
||||||
|
end
|
||||||
|
|
||||||
if is_flash?
|
if is_flash?
|
||||||
tags << "flash"
|
tags << "flash"
|
||||||
|
|||||||
Reference in New Issue
Block a user