Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Операционные системы > Мобильные ОС (Android, iOS, Windows Phone)
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 24.08.2018, 20:45   #1
ser70
Форумчанин
 
Аватар для ser70
 
Регистрация: 02.10.2009
Сообщений: 255
По умолчанию Swift Компрессия изображения с минимальными потерями качества

Здравствуйте уважаемые форумчане!
Стоит уточнить, что с языком программирования Swift и со всеми его составляющими я знаком три дня!
Нужно сжать изображение до 150 кб., чтобы на экране монитора чел. глазу не было заметно ухудшение качества изображения.
1-й алгоритм:
Код:
extension UIImage {
func compressImage() -> UIImage? {
  // Reducing file size to a 10th
var actualHeight: CGFloat = self.size.height
var actualWidth: CGFloat = self.size.width
let maxHeight: CGFloat = 800.0
let maxWidth: CGFloat = 600.0
var imgRatio: CGFloat = actualWidth/actualHeight
let maxRatio: CGFloat = maxWidth/maxHeight
var compressionQuality: CGFloat = 0.01        

if actualHeight > maxHeight || actualWidth > maxWidth {
  if imgRatio < maxRatio {
  //adjust width according to maxHeight
  imgRatio = maxHeight / actualHeight
  actualWidth = imgRatio * actualWidth
  actualHeight = maxHeight
  } else if imgRatio > maxRatio {
  //adjust height according to maxWidth
  imgRatio = maxWidth / actualWidth
  actualHeight = imgRatio * actualHeight
  actualWidth = maxWidth
  } else {
  actualHeight = maxHeight
  actualWidth = maxWidth
  compressionQuality = 1
  }
}
  let rect = CGRect(x: 0.0, y: 0.0, width: actualWidth, height:actualHeight)
  UIGraphicsBeginImageContext(rect.size) self.draw(in: rect)
  guard let img = UIGraphicsGetImageFromCurrentImageContext() else {
  return nil
  }
  UIGraphicsEndImageContext()
  guard let imageData = UIImageJPEGRepresentation(img, compressionQuality) else {
   return nil
   }
  return UIImage(data: imageData)
}
}
С этим алгоритмом ничего не получилось, искал библиотеки сжатия на Swift, ни одного не нашел! Попытался использовать алгоритм сжатия LZFSE, понял, без декомпрессора на другом устройстве(предположим с ОС Android) изображение не будет отображено, в одной из строк кода жаловался на nil-данных.
Код:
Код:
public enum CompressionAlgorithm {
  case lz4   // speed is critical
  case lz4a  // space is critical
  case zlib  // reasonable speed and space
  case lzfse // better speed and space
}
private enum CompressionOperation {
  case compression, decompression
}
private func perform(_ operation: CompressionOperation, on input: Data, using algorithm: CompressionAlgorithm, workingBufferSize: Int = 2000) -> Data?  {
  var output = Data()
  // set the algorithm
  let streamAlgorithm: compression_algorithm
  switch algorithm {
    case .lz4:   streamAlgorithm = COMPRESSION_LZ4
    case .lz4a:  streamAlgorithm = COMPRESSION_LZMA
    case .zlib:  streamAlgorithm = COMPRESSION_ZLIB
    case .lzfse: streamAlgorithm = COMPRESSION_LZFSE
  }
  // set the stream operation, and flags
  let streamOperation: compression_stream_operation
  let flags: Int32
  switch operation {
    case .compression:
      streamOperation = COMPRESSION_STREAM_ENCODE
      flags = Int32(COMPRESSION_STREAM_FINALIZE.rawValue)
    case .decompression:
      streamOperation = COMPRESSION_STREAM_DECODE
      flags = 0
  }
  // create a stream
  var streamPointer = UnsafeMutablePointer<compression_stream>
    .allocate(capacity: 1)
  defer {
    streamPointer.deallocate(capacity: 1)
  }
  // initialize the stream
  var stream = streamPointer.pointee
  var status = compression_stream_init(&stream, streamOperation, streamAlgorithm)
  guard status != COMPRESSION_STATUS_ERROR else {
    return nil
  }
  defer {
    compression_stream_destroy(&stream)
  }
  // set up a destination buffer
  let dstSize = workingBufferSize
  let dstPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: dstSize)
  defer {
    dstPointer.deallocate(capacity: dstSize)
  }
  // process the input
  return input.withUnsafeBytes { (srcPointer: UnsafePointer<UInt8>) in
    stream.src_ptr = srcPointer
    stream.src_size = input.count
    stream.dst_ptr = dstPointer
    stream.dst_size = dstSize
    while status == COMPRESSION_STATUS_OK {
      // process the stream
      status = compression_stream_process(&stream, flags)
      // collect bytes from the stream and reset
      switch status {
      case COMPRESSION_STATUS_OK:
        output.append(dstPointer, count: dstSize)
        stream.dst_ptr = dstPointer
        stream.dst_size = dstSize
      case COMPRESSION_STATUS_ERROR:
        return nil
      case COMPRESSION_STATUS_END:
        output.append(dstPointer, count: stream.dst_ptr - dstPointer) 
      default:
        fatalError()
      }
    }
    return output
  }
}
// Compressed keeps the compressed data and the algorithm
// together as one unit, so you never forget how the data was
// compressed.  
public struct Compressed {
  public let data: Data
  public let algorithm: CompressionAlgorithm
  public init(data: Data, algorithm: CompressionAlgorithm) {
    self.data = data
    self.algorithm = algorithm
  }
  // Compress the input with the specified algorithm. Returns nil if it fails.
  public static func compress(input: Data, with algorithm: CompressionAlgorithm) -> Compressed? {
    guard let data = perform(.compression, on: input, using: algorithm) else {
      return nil
    }
    return Compressed(data: data, algorithm: algorithm)
  }
  // Factory method to return uncompressed data. Returns nil if it cannot be decompressed.
  public func makeDecompressed() -> Data? {
    return perform(.decompression, on: data, using: algorithm)
  }
}
// For discoverability, add a compressed method to Data
extension Data {
  // Factory method to make compressed data or nil if it fails.
  public func makeCompressed(with algorithm: CompressionAlgorithm) -> Compressed? {
    return Compressed.compress(input: self, with: algorithm)
  }
}
Вот в этой строке кода:
Код:
UIImage(data: imageCompressData)//к переменной imageCompressData был применен код сверху!
Далее случайно наткнулся на этот код:
Код:
func resizeImageUsingVImage(image:UIImage, size:CGSize) -> UIImage? {
  let cgImage = image.cgImage!
  var format = vImage_CGImageFormat(bitsPerComponent: 8, bitsPerPixel: 32, colorSpace: nil, bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.first.rawValue), version: 0, decode: nil, renderingIntent: CGColorRenderingIntent.defaultIntent)
  var sourceBuffer = vImage_Buffer()
  defer {
    free(sourceBuffer.data)
  }
  var error = vImageBuffer_InitWithCGImage(&sourceBuffer, &format, nil, cgImage, numericCast(kvImageNoFlags))
  guard error == kvImageNoError else { return nil }
  // create a destination buffer
  let scale = image.scale
  let destWidth = Int(size.width)
  let destHeight = Int(size.height)
  let bytesPerPixel = image.cgImage!.bitsPerPixel/8
  let destBytesPerRow = destWidth * bytesPerPixel
  let destData = UnsafeMutablePointer<UInt8>.allocate(capacity: destHeight * destBytesPerRow)
   defer {
   destData.deallocate(capacity: destHeight * destBytesPerRow)
   }
   var destBuffer = vImage_Buffer(data: destData, height: vImagePixelCount(destHeight), width: vImagePixelCount(destWidth), rowBytes: destBytesPerRow)
// scale the image
  error = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, nil, numericCast(kvImageHighQualityResampling))
  guard error == kvImageNoError else { return nil }
// create a CGImage from vImage_Buffer
  var destCGImage = vImageCreateCGImageFromBuffer(&destBuffer, &format, nil, nil, numericCast(kvImageNoFlags), &error)?.takeRetainedValue()
  guard error == kvImageNoError else { return nil }
// create a UIImage
  let resizedImage = destCGImage.flatMap { UIImage(cgImage: $0, scale: 0.0, orientation: image.imageOrientation) }
  destCGImage = nil
  return resizedImage
}
Присмотревшись к коду изучив документацию по vImage и библиотеки Accelerate понял, эта мощная библиотека обработки изображений, если бы у меня хватало знаний, я бы смог создать хороший компрессор, но знаний недостаточно, надежда на Вас.

P.S. Извините за краткость
"Реальность воображаема, а воображаемое - реально" В. Соло
ser70 вне форума Ответить с цитированием
Старый 26.08.2018, 18:37   #2
ser70
Форумчанин
 
Аватар для ser70
 
Регистрация: 02.10.2009
Сообщений: 255
По умолчанию

Есть какие-нибудь идеи?
"Реальность воображаема, а воображаемое - реально" В. Соло
ser70 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
улучшение качества изображения Лилиана1992 Мультимедиа в Delphi 2 19.04.2014 20:50
Уменьшение размера изображения на php уменьшение качества картинки пример class php jpeg gif png xzxz PHP 2 19.11.2012 11:11
жение качества(сжатие) отсканированного изображения Vivaldi7 Общие вопросы Delphi 1 11.10.2011 01:38
Потеря качества изображения при копировании Herly Общие вопросы Delphi 14 11.02.2010 20:08