You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							77 lines
						
					
					
						
							1.4 KiB
						
					
					
				
			
		
		
	
	
							77 lines
						
					
					
						
							1.4 KiB
						
					
					
				| class Base64ImageConverter
 | |
|   BASE64_HEAD = 'data:image/jpeg;base64,'.freeze
 | |
| 
 | |
|   Error         = Class.new(StandardError)
 | |
|   OutLimit      = Class.new(Error)
 | |
|   InvalidData   = Class.new(Error)
 | |
|   InvalidFormat = Class.new(Error)
 | |
| 
 | |
|   attr_reader :opts
 | |
| 
 | |
|   def initialize(**opts)
 | |
|     @opts = opts
 | |
|   end
 | |
| 
 | |
|   def convert(data)
 | |
|     raise InvalidData, '不合法的Base64数据' unless valid_base64?(data)
 | |
| 
 | |
|     io = StringIO.new(Base64.decode64(image_data data))
 | |
| 
 | |
|     raise OutLimit, '文件大小超过限制' if opts[:max_size].present? && io.size > opts[:max_size]
 | |
| 
 | |
|     raise InvalidFormat, '无效的格式' unless Image.new(io).image?
 | |
| 
 | |
|     io
 | |
|   end
 | |
| 
 | |
|   private
 | |
| 
 | |
|   def valid_base64?(data)
 | |
|     data&.start_with?(BASE64_HEAD)
 | |
|   end
 | |
| 
 | |
|   def image_data(data)
 | |
|     data[BASE64_HEAD.size..-1]
 | |
|   end
 | |
| 
 | |
|   def size_limit
 | |
|     EduSetting.get('upload_avatar_max_size')
 | |
|   end
 | |
| 
 | |
|   class Image
 | |
|     attr_reader :io
 | |
| 
 | |
|     def initialize(io)
 | |
|       raise ArgumentError unless io.respond_to?(:read)
 | |
|       @io = io
 | |
|     end
 | |
| 
 | |
|     def data
 | |
|       @_data ||= begin
 | |
|         data = io.read(9)
 | |
|         io.rewind
 | |
|         data
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     def image?
 | |
|       bitmap? || gif? || jpeg? || png?
 | |
|     end
 | |
| 
 | |
|     def bitmap?
 | |
|       data[0,2] == 66.chr + 77.chr
 | |
|     end
 | |
| 
 | |
|     def gif?
 | |
|       data[0,4] == 71.chr + 73.chr + 70.chr + 56.chr
 | |
|     end
 | |
| 
 | |
|     def jpeg?
 | |
|       data[0,3] == 0xff.chr + 0xd8.chr + 0xff.chr
 | |
|     end
 | |
| 
 | |
|     def png?
 | |
|       data[0,2] == 0x89.chr + 80.chr
 | |
|     end
 | |
|   end
 | |
| end |