在单个字节字符串中编码多个 jpeg 图像的最简单可靠的方法是什么?
What's the simplest reliable way to encode multiple jpeg images in a single byte string?
我需要发布包含多个 jpeg 图像的 Google 云 Pub/Sub 消息。它需要进入数据body。将它作为 base64 编码的字符串放在属性中是行不通的,因为属性值被限制为 1024 字节:
https://cloud.google.com/pubsub/quotas#resource_limits
执行此操作的简单可靠模式是什么?选择一些固定的分隔符似乎是可能的,但我想避免该分隔符出现在图像内部的可能性。 jpeg 字节数组中是否可能出现 ||||
之类的东西?另一种可能性似乎编码为 multi-part 哑剧,但我还没有找到任何 general-purpose non-http 库来做到这一点。我需要在 Java/Scala 和 Python 中实现。或者也许我可以在没有任何外部分隔符的情况下连接 jpeg 字节数组,并根据 header 标识符拆分它们?
看起来以下方法可能有效,用 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
}
我确信还有更高效、更实用的实施方式,但那是以后的事了!
您可能希望使用 Avro or Protocol Buffers 之类的方式将数据存储在某种 schema-based 消息中。两者都可以生成可用于序列化和反序列化 Java/Scala 和 Python.
中消息的代码
例如,在协议缓冲区中,您可以在文件中创建消息 image.proto
:
syntax = "proto3";
message Images {
bytes images = 1;
}
您可以使用 protoc 编译器为此生成 python 代码:
$ 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())
我需要发布包含多个 jpeg 图像的 Google 云 Pub/Sub 消息。它需要进入数据body。将它作为 base64 编码的字符串放在属性中是行不通的,因为属性值被限制为 1024 字节: https://cloud.google.com/pubsub/quotas#resource_limits
执行此操作的简单可靠模式是什么?选择一些固定的分隔符似乎是可能的,但我想避免该分隔符出现在图像内部的可能性。 jpeg 字节数组中是否可能出现 ||||
之类的东西?另一种可能性似乎编码为 multi-part 哑剧,但我还没有找到任何 general-purpose non-http 库来做到这一点。我需要在 Java/Scala 和 Python 中实现。或者也许我可以在没有任何外部分隔符的情况下连接 jpeg 字节数组,并根据 header 标识符拆分它们?
看起来以下方法可能有效,用 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
}
我确信还有更高效、更实用的实施方式,但那是以后的事了!
您可能希望使用 Avro or Protocol Buffers 之类的方式将数据存储在某种 schema-based 消息中。两者都可以生成可用于序列化和反序列化 Java/Scala 和 Python.
中消息的代码例如,在协议缓冲区中,您可以在文件中创建消息 image.proto
:
syntax = "proto3";
message Images {
bytes images = 1;
}
您可以使用 protoc 编译器为此生成 python 代码:
$ 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())