Какой самый простой надежный способ кодировать несколько изображений JPEG в одну строку байтов? - PullRequest
0 голосов
/ 12 июня 2019

Мне нужно опубликовать сообщение Google Cloud Pub / Sub с несколькими изображениями в формате JPEG.Это должно идти в теле данных.Размещение в качестве атрибута строки в кодировке base64 в атрибуте не сработает, поскольку значения атрибута ограничены 1024 байтами: https://cloud.google.com/pubsub/quotas#resource_limits

Какой простой и надежный шаблон для этого?Может показаться возможным выбрать какой-либо фиксированный разделитель, но я хочу избежать возможности появления этого разделителя внутри изображения.Возможно ли что-то вроде |||| может произойти в байтовом массиве jpeg?Может показаться, что другая возможность кодируется как mime из нескольких частей, но я не нашел никаких библиотек общего назначения, кроме http.Мне нужны реализации как на Java / Scala, так и на Python.Или, может быть, я могу просто конкатенировать байтовые массивы jpeg без какого-либо внешнего разделителя и разделить их на основе идентификаторов заголовка?

Ответы [ 2 ]

1 голос
/ 12 июня 2019

Вы, вероятно, хотите хранить данные в каком-либо сообщении на основе схемы, используя что-то вроде Avro или Буферы протокола .Оба могут генерировать код, который можно использовать для сериализации и десериализации сообщений в Java / Scala и Python.

Например, в буферах протокола вы можете создать сообщение в файле image.proto:

syntax = "proto3";

message Images {
  bytes images = 1;
}

Вы можете сгенерировать код Python для этого с помощью компилятора protoc:

 $ protoc -I=. --python_out=. image.proto 

В Python3, чтобы добавить изображения, сериализовать сообщение и отправить его, вы должны сделать следующее:

import image_pb2
from google.cloud import pubsub_v1

publisher = pubsub_v1.PublisherClient()
topic_path = publisher.topic_path(<project name>, <topic name>)

def send_images(images):
  img_msg = image_pb2.Images()
  for i in images:
    img_msg.images.append(i)

  msg_data = img_msg.SerializeToString()

  message_future = publisher.publish(topic_path, data=msg_data)
  print(message_future.result())

Чтобы получить изображения и обработать их:

import image_pb2
from google.cloud import pubsub_v1

def receive(message):
  images = image_pb2.Images()
  images.ParseFromString(message.data)
  for i in images.images:
    # Process the image
  message.ack()

subscriber = pubsub_v1.SubscriberClient()
subscription_path = subscriber.subscription_path(<project name>, <subscription name>)
subscribe_future = subscriber.subscribe(subscription_path, receive)
print(subscribe_future.result())
0 голосов
/ 12 июня 2019

Похоже, что следующий подход, написанный на Scala, может использовать только натуральные разделители:

  def serializeJpegs(jpegs: Seq[Array[Byte]]): Array[Byte] =
    jpegs.foldLeft(Array.empty[Byte])(_ ++ _)

  def deserializeJpegs(bytes: Array[Byte]): Seq[Array[Byte]] = {
    val JpegHeader = Array(0xFF.toByte, 0xD8.toByte)
    val JpegFooter = Array(0xFF.toByte, 0xD9.toByte)
    val Delimiter = JpegFooter ++ JpegHeader

    val jpegs: mutable.Buffer[Array[Byte]] = mutable.Buffer.empty
    var (start, end) = (0, 0)
    end = bytes.indexOfSlice(Delimiter, start) + JpegFooter.length

    while (end > JpegFooter.length) {
      jpegs += bytes.slice(start, end)
      start = end
      end = bytes.indexOfSlice(Delimiter, start) + JpegFooter.length
    }

    if (start < bytes.length) {
      jpegs += bytes.drop(start)
    }

    jpegs
  }

Я уверен, что есть более эффективная и функциональная реализация, но это на другой день!

...