Skip to content
This repository has been archived by the owner on May 16, 2022. It is now read-only.

Commit

Permalink
Upgrade png format requests to zip behind the scenes
Browse files Browse the repository at this point in the history
This saves network bandwidth (there's less to download)
  • Loading branch information
odlp committed May 19, 2020
1 parent 4c2d023 commit e40648c
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 27 deletions.
3 changes: 2 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/remove-bg/go/processor"
"github.com/spf13/cobra"
"os"
"strings"
)

const defaultLargeBatchSize = 50
Expand Down Expand Up @@ -50,7 +51,7 @@ var RootCmd = &cobra.Command{
Channels: imageChannels,
BgColor: bgColor,
BgImageFile: bgImageFile,
Format: imageFormat,
Format: strings.ToLower(imageFormat),
ExtraApiOptions: extraApiOptions,
},
}
Expand Down
15 changes: 14 additions & 1 deletion processor/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ func (p Processor) Process(rawInputPaths []string, settings Settings) {
return
}

settings.ImageSettings.upgradePngToZipFormat()

totalImages := len(inputPaths)

for index, inputPath := range inputPaths {
Expand All @@ -85,14 +87,25 @@ func (p Processor) Process(rawInputPaths []string, settings Settings) {
}
}

const FormatPng = "png"
const FormatZip = "zip"
const MimeZip = "application/zip"

func (is *ImageSettings) upgradePngToZipFormat() {
// Save network bandwidth by requesting ZIP format (output will still be a PNG)
if is.Format == FormatPng {
is.Format = FormatZip
}
}

func (p Processor) processFile(inputPath string, outputPath string, imageSettings ImageSettings) error {
params := imageSettingsToParams(imageSettings)
processedBytes, contentType, err := p.Client.RemoveFromFile(inputPath, p.APIKey, params)
if err != nil {
return err
}

if strings.Contains(contentType, "application/zip") {
if strings.Contains(contentType, MimeZip) {
return p.processCompositeFile(outputPath, processedBytes)
} else {
return p.Storage.Write(outputPath, processedBytes)
Expand Down
74 changes: 49 additions & 25 deletions processor/processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import (
"github.com/remove-bg/go/storage/storagefakes"
)

const zipMime = "application/zip"
const pngMime = "image/png"
const mimePng = "image/png"

var _ = Describe("Processor", func() {
var (
Expand Down Expand Up @@ -67,8 +66,8 @@ var _ = Describe("Processor", func() {
})

It("coordinates the HTTP request and writing the result", func() {
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Processed1"), pngMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Processed2"), pngMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Processed1"), mimePng, nil)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Processed2"), mimePng, nil)

inputPaths := []string{"dir/image1.jpg", "dir/image2.jpg"}

Expand All @@ -88,15 +87,49 @@ var _ = Describe("Processor", func() {
Expect(writerArg2).To(Equal([]byte("Processed1")))
})

Context("zip format result", func() {
Context("zip format requested", func() {
It("delegates to the compositor", func() {
fakeCompositor.ProcessReturns(nil)
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Zip1"), zipMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Zip2"), zipMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Zip1"), processor.MimeZip, nil)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Zip2"), processor.MimeZip, nil)

inputPaths := []string{"dir/image1.jpg", "dir/image2.jpg"}
testSettings.OutputDirectory = "out-dir"
testSettings.ImageSettings.Format = "zip"
testSettings.ImageSettings.Format = processor.FormatZip

subject.Process(inputPaths, testSettings)

Expect(fakeCompositor.ProcessCallCount()).To(Equal(2))

zipFileName, outputPath := fakeCompositor.ProcessArgsForCall(0)
Expect(zipFileName).To(ContainSubstring(".zip"))
Expect(outputPath).To(Equal("out-dir/image1.png"))
})
})

Context("png format requested", func() {
BeforeEach(func() {
fakeCompositor.ProcessReturns(nil)
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Zip1"), processor.MimeZip, nil)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Zip2"), processor.MimeZip, nil)
})

It("upgrades the format to zip behind the scenes", func() {
inputPaths := []string{"dir/image1.jpg", "dir/image2.jpg"}
testSettings.OutputDirectory = "out-dir"
testSettings.ImageSettings.Format = processor.FormatPng

subject.Process(inputPaths, testSettings)

Expect(fakeClient.RemoveFromFileCallCount()).To(Equal(2))
_, _, params := fakeClient.RemoveFromFileArgsForCall(0)
Expect(params["format"]).To(Equal(processor.FormatZip))
})

It("delegates to the compositor", func() {
inputPaths := []string{"dir/image1.jpg", "dir/image2.jpg"}
testSettings.OutputDirectory = "out-dir"
testSettings.ImageSettings.Format = processor.FormatPng

subject.Process(inputPaths, testSettings)

Expand All @@ -110,7 +143,7 @@ var _ = Describe("Processor", func() {

Describe("image options", func() {
It("passes non-empty image options to the client", func() {
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Processed1"), pngMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Processed1"), mimePng, nil)
inputPaths := []string{"dir/image1.jpg"}

testSettings.ImageSettings = processor.ImageSettings{
Expand All @@ -122,15 +155,6 @@ var _ = Describe("Processor", func() {
Format: "format-value",
}

testSettings.ImageSettings = processor.ImageSettings{
Size: "size-value",
Type: "type-value",
Channels: "channels-value",
BgColor: "bg-color-value",
BgImageFile: "bg-image-file-value",
Format: "format-value",
}

subject.Process(inputPaths, testSettings)

Expect(fakeClient.RemoveFromFileCallCount()).To(Equal(1))
Expand All @@ -145,7 +169,7 @@ var _ = Describe("Processor", func() {
})

It("parses any extra API options into params", func() {
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Processed1"), pngMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Processed1"), mimePng, nil)
inputPaths := []string{"dir/image1.jpg"}

testSettings.ImageSettings = processor.ImageSettings{
Expand All @@ -167,7 +191,7 @@ var _ = Describe("Processor", func() {
Context("client error", func() {
It("keeps processing images", func() {
fakeClient.RemoveFromFileReturnsOnCall(0, nil, "", errors.New("boom"))
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Processed2"), pngMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Processed2"), mimePng, nil)
inputPaths := []string{"dir/image1.jpg", "dir/image2.jpg"}

subject.Process(inputPaths, testSettings)
Expand All @@ -184,7 +208,7 @@ var _ = Describe("Processor", func() {
It("passes the error details to the notifier", func() {
err := errors.New("boom")
fakeClient.RemoveFromFileReturnsOnCall(0, nil, "", err)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Processed2"), pngMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Processed2"), mimePng, nil)
inputPaths := []string{"dir/image1.jpg", "dir/image2.jpg"}

subject.Process(inputPaths, testSettings)
Expand All @@ -202,8 +226,8 @@ var _ = Describe("Processor", func() {

Context("writer error", func() {
It("keeps processing images", func() {
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Processed1"), pngMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Processed2"), pngMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Processed1"), mimePng, nil)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Processed2"), mimePng, nil)
fakeStorage.WriteReturnsOnCall(0, errors.New("boom"))
inputPaths := []string{"dir/image1.jpg", "dir/image2.jpg"}

Expand All @@ -216,8 +240,8 @@ var _ = Describe("Processor", func() {

It("passes the error details to the notifier", func() {
err := errors.New("boom")
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Processed1"), pngMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Processed2"), pngMime, nil)
fakeClient.RemoveFromFileReturnsOnCall(0, []byte("Processed1"), mimePng, nil)
fakeClient.RemoveFromFileReturnsOnCall(1, []byte("Processed2"), mimePng, nil)
fakeStorage.WriteReturnsOnCall(0, err)
inputPaths := []string{"dir/image1.jpg", "dir/image2.jpg"}

Expand Down

0 comments on commit e40648c

Please sign in to comment.