From f6cc5af43f6f1f803b91f2a58c5f34671e5d1a56 Mon Sep 17 00:00:00 2001 From: Janos Dobronszki Date: Mon, 24 May 2021 15:54:37 +0100 Subject: [PATCH] Crop images optionally after resizing (#125) --- image/handler/image.go | 21 +++ image/proto/image.pb.go | 393 ++++++++++++++++++++++++++++++++-------- image/proto/image.proto | 27 +++ 3 files changed, 369 insertions(+), 72 deletions(-) diff --git a/image/handler/image.go b/image/handler/image.go index 6df8411..e7c13bc 100644 --- a/image/handler/image.go +++ b/image/handler/image.go @@ -149,6 +149,27 @@ func (e *Image) Resize(ctx context.Context, req *img.ResizeRequest, rsp *img.Res } resultImage := imaging.Resize(srcImage, int(req.Width), int(req.Height), imaging.Lanczos) + if req.CropOptions != nil { + anchor := imaging.Center + switch req.CropOptions.Anchor { + case "top left": + anchor = imaging.TopLeft + case "top": + anchor = imaging.Top + case "top right": + anchor = imaging.TopRight + case "left": + anchor = imaging.Left + case "bottom left": + anchor = imaging.BottomLeft + case "bottom": + anchor = imaging.Bottom + case "bottom right": + anchor = imaging.BottomRight + } + resultImage = imaging.CropAnchor(resultImage, int(req.Width), int(req.Height), + anchor) + } buf := new(bytes.Buffer) switch { diff --git a/image/proto/image.pb.go b/image/proto/image.pb.go index 56d3d45..d40f74a 100644 --- a/image/proto/image.pb.go +++ b/image/proto/image.pb.go @@ -136,7 +136,188 @@ func (x *UploadResponse) GetUrl() string { return "" } +type Point struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + X int32 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"` + Y int32 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"` +} + +func (x *Point) Reset() { + *x = Point{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_image_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Point) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Point) ProtoMessage() {} + +func (x *Point) ProtoReflect() protoreflect.Message { + mi := &file_proto_image_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Point.ProtoReflect.Descriptor instead. +func (*Point) Descriptor() ([]byte, []int) { + return file_proto_image_proto_rawDescGZIP(), []int{2} +} + +func (x *Point) GetX() int32 { + if x != nil { + return x.X + } + return 0 +} + +func (x *Point) GetY() int32 { + if x != nil { + return x.Y + } + return 0 +} + +type Rectangle struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Min *Point `protobuf:"bytes,1,opt,name=min,proto3" json:"min,omitempty"` + Max *Point `protobuf:"bytes,2,opt,name=max,proto3" json:"max,omitempty"` +} + +func (x *Rectangle) Reset() { + *x = Rectangle{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_image_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Rectangle) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Rectangle) ProtoMessage() {} + +func (x *Rectangle) ProtoReflect() protoreflect.Message { + mi := &file_proto_image_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Rectangle.ProtoReflect.Descriptor instead. +func (*Rectangle) Descriptor() ([]byte, []int) { + return file_proto_image_proto_rawDescGZIP(), []int{3} +} + +func (x *Rectangle) GetMin() *Point { + if x != nil { + return x.Min + } + return nil +} + +func (x *Rectangle) GetMax() *Point { + if x != nil { + return x.Max + } + return nil +} + +type CropOptions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // width to crop to + Width int32 `protobuf:"varint,1,opt,name=width,proto3" json:"width,omitempty"` + // height to crop to + Height int32 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` + // Crop anchor point: "top", "top left", "top right", + // "left", "center", "right" + // "bottom left", "bottom", "bottom right". + // Optional. Defaults to center. + Anchor string `protobuf:"bytes,3,opt,name=anchor,proto3" json:"anchor,omitempty"` +} + +func (x *CropOptions) Reset() { + *x = CropOptions{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_image_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CropOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CropOptions) ProtoMessage() {} + +func (x *CropOptions) ProtoReflect() protoreflect.Message { + mi := &file_proto_image_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CropOptions.ProtoReflect.Descriptor instead. +func (*CropOptions) Descriptor() ([]byte, []int) { + return file_proto_image_proto_rawDescGZIP(), []int{4} +} + +func (x *CropOptions) GetWidth() int32 { + if x != nil { + return x.Width + } + return 0 +} + +func (x *CropOptions) GetHeight() int32 { + if x != nil { + return x.Height + } + return 0 +} + +func (x *CropOptions) GetAnchor() string { + if x != nil { + return x.Anchor + } + return "" +} + // Resize an image on the fly without storing it (by sending and receiving a base64 encoded image), or resize and upload depending on parameters. +// If one of width or height is 0, the image aspect ratio is preserved. +// Optional cropping. type ResizeRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -153,12 +334,16 @@ type ResizeRequest struct { OutputURL bool `protobuf:"varint,4,opt,name=outputURL,proto3" json:"outputURL,omitempty"` Width int64 `protobuf:"varint,5,opt,name=width,proto3" json:"width,omitempty"` Height int64 `protobuf:"varint,6,opt,name=height,proto3" json:"height,omitempty"` + // optional crop options + // if provided, after resize, the image + // will be cropped + CropOptions *CropOptions `protobuf:"bytes,7,opt,name=cropOptions,proto3" json:"cropOptions,omitempty"` } func (x *ResizeRequest) Reset() { *x = ResizeRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_image_proto_msgTypes[2] + mi := &file_proto_image_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -171,7 +356,7 @@ func (x *ResizeRequest) String() string { func (*ResizeRequest) ProtoMessage() {} func (x *ResizeRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_image_proto_msgTypes[2] + mi := &file_proto_image_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -184,7 +369,7 @@ func (x *ResizeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResizeRequest.ProtoReflect.Descriptor instead. func (*ResizeRequest) Descriptor() ([]byte, []int) { - return file_proto_image_proto_rawDescGZIP(), []int{2} + return file_proto_image_proto_rawDescGZIP(), []int{5} } func (x *ResizeRequest) GetBase64() string { @@ -229,6 +414,13 @@ func (x *ResizeRequest) GetHeight() int64 { return 0 } +func (x *ResizeRequest) GetCropOptions() *CropOptions { + if x != nil { + return x.CropOptions + } + return nil +} + type ResizeResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -241,7 +433,7 @@ type ResizeResponse struct { func (x *ResizeResponse) Reset() { *x = ResizeResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_image_proto_msgTypes[3] + mi := &file_proto_image_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -254,7 +446,7 @@ func (x *ResizeResponse) String() string { func (*ResizeResponse) ProtoMessage() {} func (x *ResizeResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_image_proto_msgTypes[3] + mi := &file_proto_image_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -267,7 +459,7 @@ func (x *ResizeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ResizeResponse.ProtoReflect.Descriptor instead. func (*ResizeResponse) Descriptor() ([]byte, []int) { - return file_proto_image_proto_rawDescGZIP(), []int{3} + return file_proto_image_proto_rawDescGZIP(), []int{6} } func (x *ResizeResponse) GetBase64() string { @@ -305,7 +497,7 @@ type ConvertRequest struct { func (x *ConvertRequest) Reset() { *x = ConvertRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_image_proto_msgTypes[4] + mi := &file_proto_image_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -318,7 +510,7 @@ func (x *ConvertRequest) String() string { func (*ConvertRequest) ProtoMessage() {} func (x *ConvertRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_image_proto_msgTypes[4] + mi := &file_proto_image_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -331,7 +523,7 @@ func (x *ConvertRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConvertRequest.ProtoReflect.Descriptor instead. func (*ConvertRequest) Descriptor() ([]byte, []int) { - return file_proto_image_proto_rawDescGZIP(), []int{4} + return file_proto_image_proto_rawDescGZIP(), []int{7} } func (x *ConvertRequest) GetBase64() string { @@ -374,7 +566,7 @@ type ConvertResponse struct { func (x *ConvertResponse) Reset() { *x = ConvertResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_image_proto_msgTypes[5] + mi := &file_proto_image_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -387,7 +579,7 @@ func (x *ConvertResponse) String() string { func (*ConvertResponse) ProtoMessage() {} func (x *ConvertResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_image_proto_msgTypes[5] + mi := &file_proto_image_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -400,7 +592,7 @@ func (x *ConvertResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ConvertResponse.ProtoReflect.Descriptor instead. func (*ConvertResponse) Descriptor() ([]byte, []int) { - return file_proto_image_proto_rawDescGZIP(), []int{5} + return file_proto_image_proto_rawDescGZIP(), []int{8} } func (x *ConvertResponse) GetBase64() string { @@ -429,47 +621,62 @@ var file_proto_image_proto_rawDesc = []byte{ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x44, 0x22, 0x22, 0x0a, 0x0e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x75, 0x72, 0x6c, 0x22, 0x9f, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x18, + 0x75, 0x72, 0x6c, 0x22, 0x23, 0x0a, 0x05, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x0c, 0x0a, 0x01, + 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x79, 0x22, 0x4b, 0x0a, 0x09, 0x52, 0x65, 0x63, 0x74, + 0x61, 0x6e, 0x67, 0x6c, 0x65, 0x12, 0x1e, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x52, 0x03, 0x6d, 0x61, 0x78, 0x22, 0x53, 0x0a, 0x0b, 0x43, 0x72, 0x6f, 0x70, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x22, 0xd5, 0x01, 0x0a, 0x0d, 0x52, + 0x65, 0x73, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, + 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, + 0x73, 0x65, 0x36, 0x34, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x49, + 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x44, + 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x55, 0x52, 0x4c, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x55, 0x52, 0x4c, 0x12, 0x14, + 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x34, 0x0a, 0x0b, + 0x63, 0x72, 0x6f, 0x70, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x72, 0x6f, 0x70, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0b, 0x63, 0x72, 0x6f, 0x70, 0x4f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0x3a, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x12, 0x10, 0x0a, 0x03, + 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x72, + 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6d, + 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6d, 0x61, + 0x67, 0x65, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x55, 0x52, + 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x55, + 0x52, 0x4c, 0x22, 0x3b, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x12, 0x10, 0x0a, - 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, - 0x18, 0x0a, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x55, 0x52, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x55, 0x52, 0x4c, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, - 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x68, - 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3a, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, - 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x12, - 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, - 0x6c, 0x22, 0x72, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, 0x12, 0x10, 0x0a, 0x03, 0x75, - 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x18, 0x0a, - 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x69, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x55, 0x52, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x55, 0x52, 0x4c, 0x22, 0x3b, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, 0x73, 0x65, - 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x73, 0x65, 0x36, 0x34, - 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, - 0x72, 0x6c, 0x32, 0xb5, 0x01, 0x0a, 0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x06, - 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x14, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x55, - 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x69, - 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x12, - 0x14, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, - 0x73, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3a, - 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x12, 0x15, 0x2e, 0x69, 0x6d, 0x61, 0x67, - 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x16, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2f, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x32, + 0xb5, 0x01, 0x0a, 0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x55, 0x70, 0x6c, + 0x6f, 0x61, 0x64, 0x12, 0x14, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x55, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x14, 0x2e, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x69, 0x7a, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x07, 0x43, + 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x12, 0x15, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x43, + 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x3b, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -484,27 +691,33 @@ func file_proto_image_proto_rawDescGZIP() []byte { return file_proto_image_proto_rawDescData } -var file_proto_image_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_proto_image_proto_msgTypes = make([]protoimpl.MessageInfo, 9) var file_proto_image_proto_goTypes = []interface{}{ (*UploadRequest)(nil), // 0: image.UploadRequest (*UploadResponse)(nil), // 1: image.UploadResponse - (*ResizeRequest)(nil), // 2: image.ResizeRequest - (*ResizeResponse)(nil), // 3: image.ResizeResponse - (*ConvertRequest)(nil), // 4: image.ConvertRequest - (*ConvertResponse)(nil), // 5: image.ConvertResponse + (*Point)(nil), // 2: image.Point + (*Rectangle)(nil), // 3: image.Rectangle + (*CropOptions)(nil), // 4: image.CropOptions + (*ResizeRequest)(nil), // 5: image.ResizeRequest + (*ResizeResponse)(nil), // 6: image.ResizeResponse + (*ConvertRequest)(nil), // 7: image.ConvertRequest + (*ConvertResponse)(nil), // 8: image.ConvertResponse } var file_proto_image_proto_depIdxs = []int32{ - 0, // 0: image.Image.Upload:input_type -> image.UploadRequest - 2, // 1: image.Image.Resize:input_type -> image.ResizeRequest - 4, // 2: image.Image.Convert:input_type -> image.ConvertRequest - 1, // 3: image.Image.Upload:output_type -> image.UploadResponse - 3, // 4: image.Image.Resize:output_type -> image.ResizeResponse - 5, // 5: image.Image.Convert:output_type -> image.ConvertResponse - 3, // [3:6] is the sub-list for method output_type - 0, // [0:3] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 2, // 0: image.Rectangle.min:type_name -> image.Point + 2, // 1: image.Rectangle.max:type_name -> image.Point + 4, // 2: image.ResizeRequest.cropOptions:type_name -> image.CropOptions + 0, // 3: image.Image.Upload:input_type -> image.UploadRequest + 5, // 4: image.Image.Resize:input_type -> image.ResizeRequest + 7, // 5: image.Image.Convert:input_type -> image.ConvertRequest + 1, // 6: image.Image.Upload:output_type -> image.UploadResponse + 6, // 7: image.Image.Resize:output_type -> image.ResizeResponse + 8, // 8: image.Image.Convert:output_type -> image.ConvertResponse + 6, // [6:9] is the sub-list for method output_type + 3, // [3:6] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_proto_image_proto_init() } @@ -538,7 +751,7 @@ func file_proto_image_proto_init() { } } file_proto_image_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResizeRequest); i { + switch v := v.(*Point); i { case 0: return &v.state case 1: @@ -550,7 +763,7 @@ func file_proto_image_proto_init() { } } file_proto_image_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResizeResponse); i { + switch v := v.(*Rectangle); i { case 0: return &v.state case 1: @@ -562,7 +775,7 @@ func file_proto_image_proto_init() { } } file_proto_image_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConvertRequest); i { + switch v := v.(*CropOptions); i { case 0: return &v.state case 1: @@ -574,6 +787,42 @@ func file_proto_image_proto_init() { } } file_proto_image_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResizeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_image_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResizeResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_image_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ConvertRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_image_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ConvertResponse); i { case 0: return &v.state @@ -592,7 +841,7 @@ func file_proto_image_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_image_proto_rawDesc, NumEnums: 0, - NumMessages: 6, + NumMessages: 9, NumExtensions: 0, NumServices: 1, }, diff --git a/image/proto/image.proto b/image/proto/image.proto index 1130218..d56b36b 100644 --- a/image/proto/image.proto +++ b/image/proto/image.proto @@ -26,8 +26,31 @@ message UploadResponse { string url = 1; } +message Point { + int32 x = 1; + int32 y = 2; +} + +message Rectangle { + Point min = 1; + Point max = 2; +} + +message CropOptions { + // width to crop to + int32 width = 1; + // height to crop to + int32 height = 2; + // Crop anchor point: "top", "top left", "top right", + // "left", "center", "right" + // "bottom left", "bottom", "bottom right". + // Optional. Defaults to center. + string anchor = 3; +} // Resize an image on the fly without storing it (by sending and receiving a base64 encoded image), or resize and upload depending on parameters. +// If one of width or height is 0, the image aspect ratio is preserved. +// Optional cropping. message ResizeRequest { // base64 encoded image to resize, // ie. "data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" @@ -40,6 +63,10 @@ message ResizeRequest { bool outputURL = 4; int64 width = 5; int64 height = 6; + // optional crop options + // if provided, after resize, the image + // will be cropped + CropOptions cropOptions = 7; } message ResizeResponse {