Улучшено из ответа @ Danny182, я также добавил обрезку белого пространства (любые пиксели ярче, чем 0xe0e0e0) для моей собственной потребности.
Использование:
let newimage = UIImage(named: "XXX")!.trim()
import UIKit
extension UIImage {
func trim() -> UIImage {
let newRect = self.cropRect
if let imageRef = self.cgImage!.cropping(to: newRect) {
return UIImage(cgImage: imageRef)
}
return self
}
var cropRect: CGRect {
let cgImage = self.cgImage
let context = createARGBBitmapContextFromImage(inImage: cgImage!)
if context == nil {
return CGRect.zero
}
let height = CGFloat(cgImage!.height)
let width = CGFloat(cgImage!.width)
let rect = CGRect(x: 0, y: 0, width: width, height: height)
context?.draw(cgImage!, in: rect)
//let data = UnsafePointer<CUnsignedChar>(CGBitmapContextGetData(context))
guard let data = context?.data?.assumingMemoryBound(to: UInt8.self) else {
return CGRect.zero
}
var lowX = width
var lowY = height
var highX: CGFloat = 0
var highY: CGFloat = 0
let heightInt = Int(height)
let widthInt = Int(width)
//Filter through data and look for non-transparent pixels.
for y in (0 ..< heightInt) {
let y = CGFloat(y)
for x in (0 ..< widthInt) {
let x = CGFloat(x)
let pixelIndex = (width * y + x) * 4 /* 4 for A, R, G, B */
if data[Int(pixelIndex)] == 0 { continue } // crop transparent
if data[Int(pixelIndex+1)] > 0xE0 && data[Int(pixelIndex+2)] > 0xE0 && data[Int(pixelIndex+3)] > 0xE0 { continue } // crop white
if (x < lowX) {
lowX = x
}
if (x > highX) {
highX = x
}
if (y < lowY) {
lowY = y
}
if (y > highY) {
highY = y
}
}
}
return CGRect(x: lowX, y: lowY, width: highX - lowX, height: highY - lowY)
}
func createARGBBitmapContextFromImage(inImage: CGImage) -> CGContext? {
let width = inImage.width
let height = inImage.height
let bitmapBytesPerRow = width * 4
let bitmapByteCount = bitmapBytesPerRow * height
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapData = malloc(bitmapByteCount)
if bitmapData == nil {
return nil
}
let context = CGContext (data: bitmapData,
width: width,
height: height,
bitsPerComponent: 8, // bits per component
bytesPerRow: bitmapBytesPerRow,
space: colorSpace,
bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue)
return context
}
}
Метод
blockquote>EventTarget.removeEventListener()
удаляет из EventTarget прослушиватель событий, ранее зарегистрированный в EventTarget.addEventListener (). Прослушиватель событий, который необходимо удалить, идентифицируется с использованием комбинации типа события, самой функции прослушивателя событий и различных необязательных опций, которые могут влиять на процесс сопоставления.Когда вы используете
Function#bind
, методbind()
создает новую функцию , для которой при вызове для этого ключевого слова установлено ключевое значение с заданной последовательностью аргументов, предшествующей любому, предоставленному при вызове новой функции.Следовательно, при использовании
removeEventListener
вы не передаете ту же ссылку на функцию, которая была добавлена дляaddEventListener
.Кэшировали
Handler function
в переменную, которая может использоваться для обоих,addEventListener
, а такжеremoveEventListener
let handlerFunction = handler.bind(null, name, callback); document.addEventListener(name, handlerFunction, false); document.removeEventListener(name, handlerFunction, false);
Вам нужно сохранить ссылку на связанную функцию, чтобы с ней позже можно было вызвать removeEventListener
:
const boundHandler = handler.bind(null, name, callback);
document.addEventListener(name, boundHandler, false);
// later:
document.removeEventListener(name, boundHandler, false);