Documentation
¶
Overview ¶
Package photos is the client library for the Photos.sh HTTP API: image tools for product photos. It removes backgrounds, resizes and compresses, upscales, erases objects and text, checks photos against marketplace rules and fixes them, and reads barcodes, text and label details. It also enhances, crops, watermarks, expands, vectorizes, denoises and colorizes photos, selects an object at a point, finds, hides and restores faces, frames identity photos, and lists colours and writes captions.
Make a client with your API key (or leave it empty to use the PHOTOS_API_KEY environment variable) and call a method with an image:
client, err := photos.New("")
if err != nil {
log.Fatal(err)
}
img, err := client.RemoveBackground(ctx, photos.File("shoe.jpg"), nil)
if err != nil {
log.Fatal(err)
}
err = img.Save("shoe.png")
Images ¶
An image argument is an Input: File for a path, Bytes for data in memory, Reader for a stream. Uploads are streamed. Methods that change a photo return an *Image (the bytes, the content type, the size), or a result that holds one beside what the method reports, such as the faces hidden; methods that read a photo return a typed result.
Options ¶
Each method takes a pointer to its own options struct, which may be nil. A field left at its zero value is not sent, and the API then uses its own default. The few options whose zero is a value of its own (a margin of 0, an automatic correction turned off) are pointers: nil is not sent, and Int, Float and Bool make one, as in Margin: photos.Float(0).
Errors ¶
An error response from the API is an *Error with the HTTP status and the API's code and message. Test for a code with errors.Is and a sentinel (ErrUnauthorized, ErrPaymentRequired, ErrBusy…), or get the *Error with errors.As. A failure to reach the API is a *ConnectionError. A cancelled context or a passed context deadline comes back as context.Canceled or context.DeadlineExceeded.
Retries and timeouts ¶
A request that gets a 503 "busy" (or a 503 that is not the API's own, as from a proxy) is sent again, twice by default, after the Retry-After the API gives (at most 30 s) or 1 s then 2 s; so is one that fails to connect, except Jobs.Create. Nothing else is retried: not a 503 "model_unavailable", which is permanent, and not a timeout. Each attempt may take 120 s by default. See WithRetries and WithTimeout, and Input for how retries treat readers.
Jobs and webhooks ¶
Client.Jobs runs one operation on many images in the background: Create, then Wait, or give a webhook URL and check each delivery with VerifyWebhook.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
// An empty key means: use the PHOTOS_API_KEY environment variable.
client, err := photos.New("")
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
img, err := client.RemoveBackground(ctx, photos.File("shoe.jpg"), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(img.ContentType, img.Width, img.Height)
if err := img.Save("shoe.png"); err != nil {
log.Fatal(err)
}
}
Output:
Index ¶
- Constants
- Variables
- func Bool(v bool) *bool
- func Float(v float64) *float64
- func Int(v int) *int
- type Account
- type Barcode
- type BarcodesResult
- type BlurFacesOptions
- type BlurFacesResult
- type Border
- type Candidate
- type CaptionOptions
- type CaptionResult
- type CheckOptions
- type CheckResult
- type Client
- func (c *Client) Account(ctx context.Context) (*Account, error)
- func (c *Client) BlurFaces(ctx context.Context, image Input, opts *BlurFacesOptions) (*BlurFacesResult, error)
- func (c *Client) Caption(ctx context.Context, image Input, opts *CaptionOptions) (*CaptionResult, error)
- func (c *Client) Check(ctx context.Context, image Input, opts *CheckOptions) (*CheckResult, error)
- func (c *Client) Colorize(ctx context.Context, image Input, opts *ColorizeOptions) (*Image, error)
- func (c *Client) Crop(ctx context.Context, image Input, opts *CropOptions) (*Image, error)
- func (c *Client) Denoise(ctx context.Context, image Input, opts *DenoiseOptions) (*Image, error)
- func (c *Client) Enhance(ctx context.Context, image Input, opts *EnhanceOptions) (*Image, error)
- func (c *Client) Erase(ctx context.Context, image Input, opts *EraseOptions) (*Image, error)
- func (c *Client) Expand(ctx context.Context, image Input, opts *ExpandOptions) (*Image, error)
- func (c *Client) FindFaces(ctx context.Context, image Input, opts *FindFacesOptions) (*FacesResult, error)
- func (c *Client) Fix(ctx context.Context, image Input, marketplace string) (*FixResult, error)
- func (c *Client) Health(ctx context.Context) (string, error)
- func (c *Client) IDPhoto(ctx context.Context, image Input, opts *IDPhotoOptions) (*IDPhotoResult, error)
- func (c *Client) IDPhotos(ctx context.Context) ([]IDPhotoDocument, error)
- func (c *Client) Identify(ctx context.Context, images []Input, opts *IdentifyOptions) (*IdentifyResult, error)
- func (c *Client) Marketplaces(ctx context.Context) ([]Marketplace, error)
- func (c *Client) Palette(ctx context.Context, image Input, opts *PaletteOptions) (*PaletteResult, error)
- func (c *Client) Presets(ctx context.Context) ([]Preset, error)
- func (c *Client) ReadBarcodes(ctx context.Context, image Input, opts *ReadBarcodesOptions) (*BarcodesResult, error)
- func (c *Client) ReadLabel(ctx context.Context, images []Input) (*LabelResult, error)
- func (c *Client) ReadText(ctx context.Context, image Input) (*TextResult, error)
- func (c *Client) RemoveBackground(ctx context.Context, image Input, opts *RemoveBackgroundOptions) (*Image, error)
- func (c *Client) RemoveText(ctx context.Context, image Input, opts *RemoveTextOptions) (*RemoveTextResult, error)
- func (c *Client) Resize(ctx context.Context, image Input, opts *ResizeOptions) (*Image, error)
- func (c *Client) RestoreFaces(ctx context.Context, image Input, opts *RestoreFacesOptions) (*RestoreFacesResult, error)
- func (c *Client) Run(ctx context.Context, image Input, opts *RunOptions) (*Image, error)
- func (c *Client) Select(ctx context.Context, image Input, opts *SelectOptions) (*SelectResult, error)
- func (c *Client) Upscale(ctx context.Context, image Input, opts *UpscaleOptions) (*Image, error)
- func (c *Client) Vectorize(ctx context.Context, image Input, opts *VectorizeOptions) (*VectorizeResult, error)
- func (c *Client) Watermark(ctx context.Context, image Input, opts *WatermarkOptions) (*Image, error)
- func (c *Client) WebhookSecret(ctx context.Context) (*WebhookSecret, error)
- type ColorizeOptions
- type ConnectionError
- type CropOptions
- type DenoiseOptions
- type EnhanceOptions
- type EraseOptions
- type Error
- type Event
- type ExpandOptions
- type Face
- type FaceBox
- type FaceLandmarks
- type FacesResult
- type FindFacesOptions
- type Finding
- type FixResult
- type FoundText
- type IDPhotoDocument
- type IDPhotoOptions
- type IDPhotoResult
- type IdentifyLabel
- type IdentifyOptions
- type IdentifyResult
- type Image
- type Input
- type ItemError
- type Job
- type JobCounts
- type JobItem
- type JobItemResult
- func (r *JobItemResult) BlurFaces() (*BlurFacesResult, error)
- func (r *JobItemResult) Crop() (*Image, error)
- func (r *JobItemResult) Fix() (*FixResult, error)
- func (r *JobItemResult) IDPhoto() (*IDPhotoResult, error)
- func (r *JobItemResult) Image() *Image
- func (r *JobItemResult) IsImage() bool
- func (r *JobItemResult) IsJSON() bool
- func (r *JobItemResult) JSON(v any) error
- func (r *JobItemResult) RemoveBackground() (*Image, error)
- func (r *JobItemResult) RemoveText() (*RemoveTextResult, error)
- func (r *JobItemResult) RestoreFaces() (*RestoreFacesResult, error)
- func (r *JobItemResult) Select() (*SelectResult, error)
- func (r *JobItemResult) Vectorize() (*VectorizeResult, error)
- type JobRequest
- type JobSummary
- type JobWebhook
- type JobsService
- func (s *JobsService) Create(ctx context.Context, req *JobRequest) (*Job, error)
- func (s *JobsService) Delete(ctx context.Context, id string) error
- func (s *JobsService) Get(ctx context.Context, id string) (*Job, error)
- func (s *JobsService) Item(ctx context.Context, id string, n int) (*JobItemResult, error)
- func (s *JobsService) List(ctx context.Context) ([]JobSummary, error)
- func (s *JobsService) Wait(ctx context.Context, id string, opts *WaitOptions) (*Job, error)
- type LabelAlcohol
- type LabelDate
- type LabelDetails
- type LabelElectric
- type LabelGS1
- type LabelMaterial
- type LabelNutrition
- type LabelQuantity
- type LabelResult
- type Marketplace
- type Measure
- type Metrics
- type Option
- type PaletteColor
- type PaletteOptions
- type PaletteResult
- type Point
- type Preset
- type ReadBarcodesOptions
- type Rect
- type RemoveBackgroundOptions
- type RemoveTextOptions
- type RemoveTextResult
- type ResizeOptions
- type RestoreFacesOptions
- type RestoreFacesResult
- type RunOptions
- type SelectOptions
- type SelectResult
- type Subject
- type TextLine
- type TextResult
- type UpscaleOptions
- type VectorizeOptions
- type VectorizeResult
- type Verdict
- type WaitOptions
- type WatermarkOptions
- type WebhookError
- type WebhookSecret
Examples ¶
- Package
- Client.Account
- Client.BlurFaces
- Client.Caption
- Client.Check
- Client.Colorize
- Client.Crop
- Client.Denoise
- Client.Enhance
- Client.Erase
- Client.Expand
- Client.FindFaces
- Client.Fix
- Client.Health
- Client.IDPhoto
- Client.IDPhotos
- Client.Identify
- Client.Marketplaces
- Client.Palette
- Client.Presets
- Client.ReadBarcodes
- Client.ReadLabel
- Client.ReadText
- Client.RemoveBackground
- Client.RemoveBackground (Staged)
- Client.RemoveText
- Client.Resize
- Client.RestoreFaces
- Client.Run
- Client.Select
- Client.Upscale
- Client.Vectorize
- Client.Watermark
- Error
- JobItemResult.Fix
- JobsService.Create
- JobsService.Item
- JobsService.List
- JobsService.Wait
- New
- VerifyWebhook
- VerifyWebhookAt
Constants ¶
const ( // DefaultBaseURL is where the API lives unless WithBaseURL or the // PHOTOS_BASE_URL environment variable says otherwise. DefaultBaseURL = "https://api.photos.sh" // DefaultTimeout is the time one HTTP attempt may take. DefaultTimeout = 120 * time.Second // DefaultRetries is how many times a request is sent again after a 503 // or a connection failure. DefaultRetries = 2 )
const ( CodeBadRequest = "bad_request" // 400: a parameter or the image is wrong CodePaymentRequired = "payment_required" // 402: out of credits CodeAccountSuspended = "account_suspended" // 403 CodeNotFound = "not_found" // 404: no such job or item result CodePayloadTooLarge = "payload_too_large" // 413 CodeUnsupportedFormat = "unsupported_format" // 415 CodeUnprocessable = "unprocessable" // 422: understood, but cannot be done CodeBusy = "busy" // 503: all workers busy; retried for you CodeInternal = "internal" // 500 // input URL could not be fetched. CodeInputUnavailable = "input_unavailable" )
Error codes the API answers with, in Error.Code.
const ( OperationRun = "run" OperationRemoveBackground = "remove-background" OperationResize = "resize" OperationUpscale = "upscale" OperationReadText = "ocr" OperationReadBarcodes = "barcodes" OperationCheck = "check" OperationFix = "fix" OperationRemoveText = "remove-text" OperationReadLabel = "label" OperationEnhance = "enhance" OperationCrop = "crop" OperationPalette = "palette" OperationWatermark = "watermark" // with text only: an item is one image OperationExpand = "expand" OperationVectorize = "vectorize" OperationFindFaces = "faces" OperationBlurFaces = "blur-faces" OperationIDPhoto = "id-photo" OperationDenoise = "denoise" OperationColorize = "colorize" OperationSelect = "select" OperationRestoreFaces = "restore-faces" OperationCaption = "caption" )
Operations a job can run, for JobRequest.Operation.
const ( JobQueued = "queued" JobRunning = "running" // JobCompleted means every item was attempted; Job.Counts says how many // failed. JobCompleted = "completed" )
Job statuses, in Job.Status.
const ( ItemPending = "pending" ItemDone = "done" ItemFailed = "failed" )
Item statuses, in JobItem.Status.
const ( DefaultWaitInterval = 2 * time.Second DefaultWaitTimeout = 10 * time.Minute )
Defaults of Jobs.Wait.
const ( FormatPNG = "png" FormatJPEG = "jpg" FormatWebP = "webp" FormatAVIF = "avif" )
Output formats, for the Format field of the options.
const ( FitContain = "contain" // keep the proportions, fit inside (the default) FitCover = "cover" // keep the proportions, fill and crop FitFill = "fill" // stretch to exactly Width × Height )
How Resize fits an image into Width × Height, for ResizeOptions.Fit.
const ( RegionBackground = "background" // text off the product (the default) RegionAll = "all" // text on the product too )
Which text RemoveText removes, for RemoveTextOptions.Region.
const ( HealthOK = "ok" // ready HealthLoading = "loading" // still loading its models HealthFailed = "failed" // a model could not be loaded )
Health statuses.
const ( // SignatureHeader is the header a webhook's signature arrives in. SignatureHeader = "Photos-Signature" // DefaultWebhookTolerance is how far a webhook's timestamp may be from // now when VerifyWebhook is given no tolerance. DefaultWebhookTolerance = 5 * time.Minute // EventJobCompleted is the Type of the event sent when a job is done. EventJobCompleted = "job.completed" )
const MaxImagesPerRequest = 8
MaxImagesPerRequest is how many photos ReadLabel and Identify take.
const Version = "1.0.0"
Version is the version of this library.
Variables ¶
var ( ErrBadRequest error = &Error{Code: CodeBadRequest} ErrPaymentRequired error = &Error{Code: CodePaymentRequired} ErrAccountSuspended error = &Error{Code: CodeAccountSuspended} ErrNotFound error = &Error{Code: CodeNotFound} ErrPayloadTooLarge error = &Error{Code: CodePayloadTooLarge} ErrUnsupportedFormat error = &Error{Code: CodeUnsupportedFormat} ErrUnprocessable error = &Error{Code: CodeUnprocessable} ErrBusy error = &Error{Code: CodeBusy} ErrInternal error = &Error{Code: CodeInternal} )
Sentinels for errors.Is, one per error code.
var ( // ErrMissingAPIKey is returned by New when no key was given and // PHOTOS_API_KEY is not set. ErrMissingAPIKey = errors.New("photos: no API key: pass one to New or set PHOTOS_API_KEY") // ErrWaitTimeout is returned (wrapped) by Jobs.Wait when the job did not // complete within WaitOptions.Timeout. ErrWaitTimeout = errors.New("photos: timed out waiting for the job") // ErrMissingResultHeaders is returned (wrapped) by JobItemResult.RemoveText, // JobItemResult.Fix and the other typed results of a job item when the // result does not carry the headers they read: it is the result of // another operation, or the engine is too old to keep those headers on // job items. ErrMissingResultHeaders = errors.New("photos: the job item result lacks the headers") )
Errors that are not responses from the API.
var ( // ErrWebhookHeader: the Photos-Signature header is missing or malformed. ErrWebhookHeader error = &WebhookError{Reason: "missing or malformed Photos-Signature header"} // ErrWebhookSignature: the signature does not match the body and secret. ErrWebhookSignature error = &WebhookError{Reason: "signature does not match"} // ErrWebhookTimestamp: the timestamp is outside the tolerance. ErrWebhookTimestamp error = &WebhookError{Reason: "timestamp outside the tolerance"} // ErrWebhookPayload: the signature is right but the body is not an event. ErrWebhookPayload error = &WebhookError{Reason: "body is not a JSON event"} )
Why a webhook is rejected.
Functions ¶
Types ¶
type Account ¶
type Account struct {
Account string `json:"account,omitempty"`
// Key is the key's id, "browser" or "job".
Key string `json:"key,omitempty"`
// Credits is the balance, nil for an unlimited account.
Credits *int64 `json:"credits,omitempty"`
// Prices are the credits one image costs, by operation.
Prices map[string]int64 `json:"prices,omitempty"`
// Unlimited is true for a server key, which is not metered.
Unlimited bool `json:"unlimited,omitempty"`
// Raw is the response as it came.
Raw json.RawMessage `json:"-"`
}
Account is the caller's account.
func (*Account) UnmarshalJSON ¶
UnmarshalJSON decodes the account and keeps the JSON in Raw.
type Barcode ¶
type Barcode struct {
// Format is the symbology: "EAN-13", "UPC-A", "ITF", "QR"…
Format string `json:"format"`
// Value is the code as decoded.
Value string `json:"value"`
// GS1 is the GS1-valid normalised digits of a retail code, else nil.
GS1 *string `json:"gs1"`
}
Barcode is one code read from a photo.
type BarcodesResult ¶
type BarcodesResult struct {
Barcodes []Barcode `json:"barcodes"`
// Variant is the preprocessing that found the codes, or "none".
Variant string `json:"variant"`
// Raw is the response as it came.
Raw json.RawMessage `json:"-"`
}
BarcodesResult is what ReadBarcodes returns.
func (*BarcodesResult) UnmarshalJSON ¶
func (r *BarcodesResult) UnmarshalJSON(data []byte) (err error)
UnmarshalJSON decodes the result and keeps the JSON in Raw.
type BlurFacesOptions ¶
type BlurFacesOptions struct {
// Mode is "blur" (the default), "pixelate" or "fill". Only "fill" leaves
// nothing of the face.
Mode string
// Strength is how strong the blur or how coarse the mosaic is, 1–100
// (default 50).
Strength float64
// Padding is how far past the face's box the hidden area reaches, as a
// fraction of the box, 0 to 1 (default 0.15). It is a pointer because 0
// (the box itself) is a value: use Float.
Padding *float64
// Color is the colour for the "fill" mode: "black" (the default),
// "white", "#rrggbb".
Color string
// MinScore is how sure the model must be that something is a face,
// 0.1–1 (default 0.6). Lower finds more faces and more things that are
// not.
MinScore float64
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
BlurFacesOptions are the options of BlurFaces. Zero fields are not sent.
type BlurFacesResult ¶
type BlurFacesResult struct {
Image
// Faces is how many faces were found and hidden (X-Faces). Check it
// before relying on the result: a face that was not found still shows.
Faces int
}
BlurFacesResult is the image BlurFaces returns, and how many faces it hid.
type Border ¶
type Border struct {
// Mean is the mean colour (red, green, blue).
Mean []float64 `json:"mean"`
// White is the share of the border that is pure white.
White float64 `json:"white"`
// Cast is (red−green, blue−green) of a light backdrop, or nil.
Cast []float64 `json:"cast"`
}
Border describes the edge of a photo: its backdrop.
type Candidate ¶
type Candidate struct {
ProductID string `json:"product_id"`
Title string `json:"title"`
Score float64 `json:"score"`
// Evidence says what agreed beyond the name: "barcode", "barcode_text",
// "sku", "brand", and by the catalogue's kind "quantity", "pack", "spf"
// (food, cosmetics), "strength", "count" (pharmacy, household), "spec",
// "model" (electronics), "cask_number", "age", "age_weak", "vintage",
// "abv", "size" (wine and spirits).
Evidence []string `json:"evidence"`
}
Candidate is a catalogue product that may be the one in the photos.
type CaptionOptions ¶
type CaptionOptions struct {
// Detail is how much to say: "short" (one sentence, the default),
// "detailed" (two or three) or "paragraph".
Detail string
}
CaptionOptions are the options of Caption. Zero fields are not sent.
type CaptionResult ¶
type CaptionResult struct {
// Caption is the description, in English. It can be wrong: read it
// before publishing it.
Caption string `json:"caption"`
// Detail is how much was asked for: "short", "detailed" or "paragraph".
Detail string `json:"detail"`
// Width and Height are the photo's size in pixels.
Width int `json:"width"`
Height int `json:"height"`
// Raw is the response as it came.
Raw json.RawMessage `json:"-"`
}
CaptionResult is what Caption returns.
func (*CaptionResult) UnmarshalJSON ¶
func (r *CaptionResult) UnmarshalJSON(data []byte) (err error)
UnmarshalJSON decodes the result and keeps the JSON in Raw.
type CheckOptions ¶
type CheckOptions struct {
// Marketplace checks the photo against that marketplace's rules
// ("amazon", "ebay", "etsy", …; see Marketplaces).
Marketplace string
// Subject finds the product, for framing and background checks.
Subject bool
// Text reads the text in the photo.
Text bool
}
CheckOptions are the options of Check. Zero fields are not sent.
type CheckResult ¶
type CheckResult struct {
Metrics Metrics `json:"metrics"`
Findings []Finding `json:"findings"`
// Text is the text read in the photo, when it was read.
Text []FoundText `json:"text,omitempty"`
// Marketplace is the marketplace's verdict, when one was asked for.
Marketplace *Verdict `json:"marketplace,omitempty"`
// Ms is how long each step took, in milliseconds.
Ms map[string]int64 `json:"ms,omitempty"`
// Raw is the response as it came.
Raw json.RawMessage `json:"-"`
}
CheckResult is what Check returns.
func (*CheckResult) UnmarshalJSON ¶
func (r *CheckResult) UnmarshalJSON(data []byte) (err error)
UnmarshalJSON decodes the result and keeps the JSON in Raw.
type Client ¶
type Client struct {
// Jobs runs one operation on many images in the background.
Jobs *JobsService
// contains filtered or unexported fields
}
Client talks to the Photos.sh API. Make one with New and share it: it is safe for use by several goroutines at once.
func New ¶
New returns a Client that signs its requests with apiKey. An empty apiKey falls back to the PHOTOS_API_KEY environment variable; with neither, New returns ErrMissingAPIKey.
The base URL is DefaultBaseURL unless WithBaseURL or the PHOTOS_BASE_URL environment variable gives another.
Example ¶
package main
import (
"context"
"fmt"
"log"
"net/http"
"time"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, err := photos.New("your-api-key",
photos.WithBaseURL("http://localhost:8080"), // a local engine
photos.WithTimeout(60*time.Second),
photos.WithRetries(4),
photos.WithUserAgent("my-shop/1.2"),
photos.WithHTTPClient(&http.Client{}),
)
if err != nil {
log.Fatal(err)
}
status, err := client.Health(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(status)
}
Output:
func (*Client) Account ¶
Account returns the caller's account: credits left and prices, or Unlimited for a server key.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
acc, err := client.Account(context.Background())
if err != nil {
log.Fatal(err)
}
if acc.Unlimited {
fmt.Println(acc.Account, "is not metered")
} else if acc.Credits != nil {
fmt.Println(*acc.Credits, "credits left; a background removal costs", acc.Prices["remove-background"])
}
}
Output:
func (*Client) BlurFaces ¶
func (c *Client) BlurFaces(ctx context.Context, image Input, opts *BlurFacesOptions) (*BlurFacesResult, error)
BlurFaces finds every face in a photo and hides it inside an ellipse: blurred, pixelated, or covered with a colour. Blur and pixelation make a face unrecognisable to a person looking at the photo; only the "fill" mode leaves nothing of it. opts may be nil.
A small face, a face seen from behind or one mostly covered may not be found: check the result's Faces before relying on it.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.BlurFaces(context.Background(), photos.File("street.jpg"),
&photos.BlurFacesOptions{Mode: "pixelate"})
if err != nil {
log.Fatal(err)
}
fmt.Println(res.Faces, "faces hidden") // check it: a face not found still shows
if err := res.Save("street-anonymous.jpg"); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Caption ¶
func (c *Client) Caption(ctx context.Context, image Input, opts *CaptionOptions) (*CaptionResult, error)
Caption describes a photo in words: one sentence, a few, or a paragraph. The same photo always gets the same words. opts may be nil.
The description can be wrong (a colour, a count, what an object is), and it is in English only. It does not know names, brands or places unless they are written in the photo. Read it before publishing it.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.Caption(context.Background(), photos.File("shoe.jpg"), &photos.CaptionOptions{Detail: "detailed"})
if err != nil {
log.Fatal(err)
}
fmt.Println(res.Caption) // a draft, in English: read it before publishing it
}
Output:
func (*Client) Check ¶
func (c *Client) Check(ctx context.Context, image Input, opts *CheckOptions) (*CheckResult, error)
Check measures a photo's quality and, with opts.Marketplace, checks it against that marketplace's rules. opts may be nil.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.Check(context.Background(), photos.File("shoe.jpg"),
&photos.CheckOptions{Marketplace: "amazon"})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d×%d, sharpness %.2f\n", res.Metrics.Width, res.Metrics.Height, res.Metrics.Sharpness)
for _, f := range res.Findings {
fmt.Println(f.Severity, f.Code, f.Message)
}
if v := res.Marketplace; v != nil && !v.Passed {
for _, f := range v.Findings {
fmt.Println("amazon:", f.Code, f.Message)
}
}
}
Output:
func (*Client) Colorize ¶
Colorize adds colour to a black-and-white photo. The colours are guesses from what such things usually look like: skin, sky, grass and wood come out believable, while the colour of clothes, cars or walls cannot be known and is invented. A photo that already has colour is treated as black and white: its colours are replaced. Transparency is kept. opts may be nil.
Example ¶
package main
import (
"context"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
img, err := client.Colorize(context.Background(), photos.File("grandparents.jpg"), nil)
if err != nil {
log.Fatal(err)
}
if err := img.Save("grandparents-colour.jpg"); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Crop ¶
Crop finds the subject (or, with opts.Focus "face", the faces) and crops the photo to a shape around it, keeping the background.
The result's SubjectFound is false when nothing was found; the crop is then centred.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
ctx := context.Background()
img, err := client.Crop(ctx, photos.File("shoe.jpg"), &photos.CropOptions{Aspect: "4:5"})
if err != nil {
log.Fatal(err)
}
if img.SubjectFound != nil && !*img.SubjectFound {
fmt.Println("no subject found: the crop is centred")
}
// An avatar: tight around the face, with room for hair and chin.
avatar, err := client.Crop(ctx, photos.File("portrait.jpg"), &photos.CropOptions{
Focus: "face",
Zoom: true,
Padding: photos.Float(0.6),
Width: 400,
Height: 400,
})
if err != nil {
log.Fatal(err)
}
if err := avatar.Save("avatar.jpg"); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Denoise ¶
Denoise removes sensor noise and the blocks and ringing of heavy JPEG compression. It does not sharpen a blurred photo or add detail, and on a photo that is already clean it removes a little fine texture: lower opts.Strength there, or do not use it. Transparency is kept. opts may be nil.
It is slow without a GPU (about half a minute a megapixel on a CPU) and takes photos up to 12 megapixels.
Example ¶
package main
import (
"context"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
img, err := client.Denoise(context.Background(), photos.File("grainy.jpg"), &photos.DenoiseOptions{Strength: 80})
if err != nil {
log.Fatal(err)
}
if err := img.Save("clean.jpg"); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Enhance ¶
Enhance fixes light and colour. With no options it stretches the tones to the full range and takes out a colour cast; with any setting, only what is given is applied. Transparency is kept. It needs no model, and it does not denoise, deblur or recover blown highlights. opts may be nil.
Example ¶
package main
import (
"context"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
ctx := context.Background()
// No options: automatic levels and white balance.
img, err := client.Enhance(ctx, photos.File("dull.jpg"), nil)
if err != nil {
log.Fatal(err)
}
if err := img.Save("bright.jpg"); err != nil {
log.Fatal(err)
}
// Settings of your own, beside the automatic part.
_, err = client.Enhance(ctx, photos.File("dull.jpg"), &photos.EnhanceOptions{
Auto: photos.Bool(true),
Brightness: 10,
Saturation: -15,
Sharpen: 30,
})
if err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Erase ¶
Erase removes objects by painting over the areas in opts.Rects and the white parts of opts.Mask.
Example ¶
package main
import (
"context"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
img, err := client.Erase(context.Background(), photos.File("room.jpg"), &photos.EraseOptions{
Rects: []photos.Rect{{X: 40, Y: 60, Width: 200, Height: 120}},
// And/or a mask the size of the photo, white where to remove:
Mask: photos.File("room-mask.png"),
})
if err != nil {
log.Fatal(err)
}
if err := img.Save("room-clean.jpg"); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Expand ¶
Expand adds room around a photo: to a shape (opts.Aspect), or by pixels on each side. The new area continues the photo by inpainting, which suits plain and softly textured backgrounds. It does not invent content: a subject cut off at the edge stays cut off. Transparency is flattened onto white.
Example ¶
package main
import (
"context"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
ctx := context.Background()
// To a shape; the new area continues the backdrop.
img, err := client.Expand(ctx, photos.File("shoe.jpg"), &photos.ExpandOptions{Aspect: "16:9"})
if err != nil {
log.Fatal(err)
}
if err := img.Save("shoe-wide.jpg"); err != nil {
log.Fatal(err)
}
// By pixels, with a flat colour.
_, err = client.Expand(ctx, photos.File("shoe.jpg"), &photos.ExpandOptions{Left: 200, Right: 200, Fill: "white"})
if err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) FindFaces ¶
func (c *Client) FindFaces(ctx context.Context, image Input, opts *FindFacesOptions) (*FacesResult, error)
FindFaces says where the faces in a photo are: a box and five landmarks each, the surest first. It finds faces; it does not recognise who anyone is. opts may be nil.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.FindFaces(context.Background(), photos.File("group.jpg"), nil)
if err != nil {
log.Fatal(err)
}
for _, f := range res.Faces {
fmt.Printf("%.0f×%.0f at %.0f,%.0f, score %.2f, tilted %.1f°\n",
f.Box.Width, f.Box.Height, f.Box.X, f.Box.Y, f.Score, f.Roll)
fmt.Println(" nose at", f.Landmarks.Nose.X, f.Landmarks.Nose.Y)
}
}
Output:
func (*Client) Fix ¶
Fix makes a photo meet a marketplace's rules ("amazon", "ebay", "etsy", "shopify", "google", "allegro", "zalando"; see Marketplaces), and reports whether the result passes.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.Fix(context.Background(), photos.File("shoe.jpg"), "amazon")
if err != nil {
log.Fatal(err)
}
if !res.Passed {
fmt.Println("still failing:", res.Findings)
}
if err := res.Save("shoe-amazon.jpg"); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Health ¶
Health reports whether the service is ready: HealthOK, HealthLoading or HealthFailed. "loading" and "failed" arrive as a 503, which here is an answer, not an error, and is not retried. No API key is sent.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
status, err := client.Health(context.Background())
if err != nil {
log.Fatal(err)
}
if status != photos.HealthOK {
fmt.Println("not ready:", status)
}
}
Output:
func (*Client) IDPhoto ¶
func (c *Client) IDPhoto(ctx context.Context, image Input, opts *IDPhotoOptions) (*IDPhotoResult, error)
IDPhoto frames a portrait for an identity document: it levels the head, scales it to the document's head size and places it on a photo of the document's size. Give opts.Document (see IDPhotos) or the sizes.
By default the photo's own background is kept, because passport authorities do not accept edited photos: the photo is only turned, scaled and cropped. opts.Background replaces it, for uses where that is allowed.
The result's Findings list what the tool could see is wrong. It cannot judge expression, glasses, shadows, focus or likeness, so an empty list is not an approval. A photo with no face, or more than one, is refused with an ErrUnprocessable.
Example ¶
package main
import (
"context"
"errors"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.IDPhoto(context.Background(), photos.File("portrait.jpg"),
&photos.IDPhotoOptions{Document: "us-passport"})
if errors.Is(err, photos.ErrUnprocessable) {
log.Fatal("the photo must show one face") // none, or more than one
} else if err != nil {
log.Fatal(err)
}
fmt.Printf("head %.1f mm; findings: %v\n", res.HeadMm, res.Findings)
if !res.Passed {
fmt.Println("the tool saw something wrong; an empty list is still not an approval")
}
if err := res.Save("passport.jpg"); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) IDPhotos ¶
func (c *Client) IDPhotos(ctx context.Context) ([]IDPhotoDocument, error)
IDPhotos lists the documents whose photo rules IDPhoto knows: each one's photo size, head size, background and notes, with the official pages the rules were read from.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
documents, err := client.IDPhotos(context.Background())
if err != nil {
log.Fatal(err)
}
for _, d := range documents {
fmt.Printf("%s: %s, %g × %g mm, head %g–%g mm\n", d.Name, d.Title, d.WidthMm, d.HeightMm, d.HeadMinMm, d.HeadMaxMm)
if d.Alteration != "" {
fmt.Println(" ", d.Alteration)
}
}
}
Output:
func (*Client) Identify ¶
func (c *Client) Identify(ctx context.Context, images []Input, opts *IdentifyOptions) (*IdentifyResult, error)
Identify matches one to eight photos of ONE product against one of your organisation's catalogues (uploaded on the console's Catalogues page). Catalogue matching is turned on per organisation: until it is on for yours and a catalogue is uploaded, the API answers 404 (errors.Is(err, ErrNotFound)). opts may be nil.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.Identify(context.Background(),
[]photos.Input{photos.File("front.jpg"), photos.File("back.jpg")},
&photos.IdentifyOptions{Catalogue: "shoes", Top: 3})
if err != nil {
log.Fatal(err)
}
for _, c := range res.Candidates {
fmt.Println(c.ProductID, c.Title, c.Score, c.Evidence)
}
}
Output:
func (*Client) Marketplaces ¶
func (c *Client) Marketplaces(ctx context.Context) ([]Marketplace, error)
Marketplaces lists the marketplaces Check and Fix know, with their rules.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
marketplaces, err := client.Marketplaces(context.Background())
if err != nil {
log.Fatal(err)
}
for _, m := range marketplaces {
fmt.Println(m.Name, m.Title, "checked", m.Checked)
for _, rule := range m.Rules {
fmt.Println(" ", rule["check"], rule["severity"])
}
}
}
Output:
func (*Client) Palette ¶
func (c *Client) Palette(ctx context.Context, image Input, opts *PaletteOptions) (*PaletteResult, error)
Palette lists the colours an image is made of, the most common first. Transparent pixels do not count, so a cutout's palette is the subject's. It needs no model. opts may be nil.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.Palette(context.Background(), photos.File("shoe.png"), &photos.PaletteOptions{Colors: 3})
if err != nil {
log.Fatal(err)
}
for _, c := range res.Colors {
fmt.Printf("%s %.0f%%\n", c.Hex, c.Share*100)
}
}
Output:
func (*Client) Presets ¶
Presets lists the built-in presets Run takes.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
presets, err := client.Presets(context.Background())
if err != nil {
log.Fatal(err)
}
for _, p := range presets {
fmt.Println(p.Name, "-", p.Description)
}
}
Output:
func (*Client) ReadBarcodes ¶
func (c *Client) ReadBarcodes(ctx context.Context, image Input, opts *ReadBarcodesOptions) (*BarcodesResult, error)
ReadBarcodes reads the barcodes in a photo. opts may be nil.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.ReadBarcodes(context.Background(), photos.File("box.jpg"),
&photos.ReadBarcodesOptions{AllFormats: true})
if err != nil {
log.Fatal(err)
}
for _, b := range res.Barcodes {
fmt.Println(b.Format, b.Value)
}
}
Output:
func (*Client) ReadLabel ¶
ReadLabel reads product details from one to eight photos of ONE product's label: text and codes from all of them are pooled.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.ReadLabel(context.Background(), []photos.Input{
photos.File("front.jpg"),
photos.File("back.jpg"),
})
if err != nil {
log.Fatal(err)
}
label := res.Label
fmt.Println(label.Headline, label.GTIN)
if q := label.NetQuantity; q != nil {
fmt.Println(q.Value, q.Unit)
}
if label.Alcohol != nil {
fmt.Printf("%.1f%% vol\n", label.Alcohol.ABV)
}
}
Output:
func (*Client) ReadText ¶
ReadText reads the text in a photo (OCR), line by line.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.ReadText(context.Background(), photos.File("label.jpg"))
if err != nil {
log.Fatal(err)
}
for _, line := range res.Lines {
fmt.Printf("%.2f %s\n", line.Score, line.Text)
}
}
Output:
func (*Client) RemoveBackground ¶
func (c *Client) RemoveBackground(ctx context.Context, image Input, opts *RemoveBackgroundOptions) (*Image, error)
RemoveBackground cuts the subject out of its background, and can stage the cutout in the same call: on a canvas, with a shadow or a reflection, in front of a colour, an image or the photo's own blurred background. opts may be nil.
With a canvas and no subject in the photo, the result is an empty canvas and its SubjectFound is false.
Example ¶
package main
import (
"context"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
img, err := client.RemoveBackground(context.Background(), photos.File("shoe.jpg"),
&photos.RemoveBackgroundOptions{
Background: "white",
Crop: true,
Padding: 40,
Format: photos.FormatJPEG,
Quality: 90,
})
if err != nil {
log.Fatal(err)
}
if err := img.Save("shoe-white" + img.Extension()); err != nil {
log.Fatal(err)
}
}
Output:
Example (Staged) ¶
A cutout staged in the same call: on a canvas, standing on a soft shadow, in front of a backdrop of your own.
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
img, err := client.RemoveBackground(context.Background(), photos.File("shoe.jpg"),
&photos.RemoveBackgroundOptions{
Width: 1600,
Height: 1600,
Fill: 0.8,
Align: "bottom",
Shadow: "contact",
BackgroundImage: photos.File("studio.jpg"),
Format: photos.FormatJPEG,
})
if err != nil {
log.Fatal(err)
}
if img.SubjectFound != nil && !*img.SubjectFound {
fmt.Println("no subject in the photo: the canvas is empty")
}
if err := img.Save("shoe-staged.jpg"); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) RemoveText ¶
func (c *Client) RemoveText(ctx context.Context, image Input, opts *RemoveTextOptions) (*RemoveTextResult, error)
RemoveText paints out text, watermarks and captions: by default only text off the product. opts may be nil.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.RemoveText(context.Background(), photos.File("listing.jpg"),
&photos.RemoveTextOptions{Matching: `sale|€|www\.`})
if err != nil {
log.Fatal(err)
}
fmt.Printf("removed %d lines, kept %d\n", res.Removed, res.Kept)
if err := res.Save("listing-clean.jpg"); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Resize ¶
Resize resizes, converts and compresses an image. It can also trim an even border first and write a print resolution. opts may be nil.
Example ¶
package main
import (
"context"
"fmt"
"log"
"os"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
// Any io.Reader will do; here, standard input.
img, err := client.Resize(context.Background(), photos.Reader("photo.jpg", os.Stdin),
&photos.ResizeOptions{Width: 1600, Format: photos.FormatWebP, MaxBytes: 300_000})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d×%d at quality %d, %d bytes\n", img.Width, img.Height, img.Quality, len(img.Bytes))
}
Output:
func (*Client) RestoreFaces ¶
func (c *Client) RestoreFaces(ctx context.Context, image Input, opts *RestoreFacesOptions) (*RestoreFacesResult, error)
RestoreFaces finds the faces in an old, blurred, small or noisy photo and redraws each one sharp; the rest of the photo is not touched. opts may be nil.
It invents the detail: the result resembles the person, but the colour of the eyes, the teeth and the skin's texture are the model's. Do not use it where the face must be exactly the person's own, such as an identity document or evidence.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.RestoreFaces(context.Background(), photos.File("old-family.jpg"), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(res.Faces, "faces restored,", res.FacesSkipped, "left alone")
if err := res.Save("old-family-restored.jpg"); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Run ¶
Run applies a preset (opts.Preset) or a recipe (opts.Recipe) to an image.
Example ¶
package main
import (
"context"
"log"
"os"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
ctx := context.Background()
// A built-in preset (see Presets)…
img, err := client.Run(ctx, photos.File("shoe.jpg"), &photos.RunOptions{Preset: "marketplace"})
if err != nil {
log.Fatal(err)
}
if err := img.Save("shoe-marketplace.jpg"); err != nil {
log.Fatal(err)
}
// …or a recipe of your own, as TOML.
recipe, err := os.ReadFile("recipe.toml")
if err != nil {
log.Fatal(err)
}
if _, err := client.Run(ctx, photos.File("shoe.jpg"), &photos.RunOptions{Recipe: string(recipe)}); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Select ¶
func (c *Client) Select(ctx context.Context, image Input, opts *SelectOptions) (*SelectResult, error)
Select cuts out the one object at opts.Points or in opts.Box, or returns its mask. Where RemoveBackground decides for itself what the subject is, here you say.
When nothing is found at the points, the error is an ErrUnprocessable; a point outside the photo is an ErrBadRequest.
Example ¶
package main
import (
"context"
"errors"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
ctx := context.Background()
// The object at a click, cut out.
res, err := client.Select(ctx, photos.File("desk.jpg"), &photos.SelectOptions{
Points: []photos.Point{{X: 420, Y: 310}},
Exclude: []photos.Point{{X: 600, Y: 300}},
Crop: true,
})
if errors.Is(err, photos.ErrUnprocessable) {
log.Fatal("nothing was found at that point")
} else if err != nil {
log.Fatal(err)
}
fmt.Printf("score %.2f\n", res.Score)
if err := res.Save("mug.png"); err != nil {
log.Fatal(err)
}
// Its mask is what Erase takes to remove it.
mask, err := client.Select(ctx, photos.File("desk.jpg"), &photos.SelectOptions{
Points: []photos.Point{{X: 420, Y: 310}},
Mask: true,
})
if err != nil {
log.Fatal(err)
}
_, err = client.Erase(ctx, photos.File("desk.jpg"), &photos.EraseOptions{
Mask: photos.Bytes("mask.png", mask.Bytes),
})
if err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Upscale ¶
Upscale enlarges an image with an AI model. opts may be nil.
Example ¶
package main
import (
"context"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
img, err := client.Upscale(context.Background(), photos.File("small.jpg"), &photos.UpscaleOptions{Scale: 2})
if err != nil {
log.Fatal(err)
}
if err := img.Save("large.jpg"); err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) Vectorize ¶
func (c *Client) Vectorize(ctx context.Context, image Input, opts *VectorizeOptions) (*VectorizeResult, error)
Vectorize traces an image into SVG: each area of one colour becomes a filled path. It is for logos, icons and flat drawings; a photograph traces into thousands of paths and a large file. Images over 2000 pixels on a side are traced from a smaller copy. It needs no model. opts may be nil.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
res, err := client.Vectorize(context.Background(), photos.File("logo.png"), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(res.Paths, "paths, traced at", res.Width, "×", res.Height)
if err := res.Save("logo.svg"); err != nil { // res.Bytes is the SVG's text
log.Fatal(err)
}
}
Output:
func (*Client) Watermark ¶
func (c *Client) Watermark(ctx context.Context, image Input, opts *WatermarkOptions) (*Image, error)
Watermark puts opts.Text or the image opts.Watermark (a logo) on a photo: at one of nine positions, or tiled across it. It needs no model.
Example ¶
package main
import (
"context"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
ctx := context.Background()
// Text…
img, err := client.Watermark(ctx, photos.File("photo.jpg"), &photos.WatermarkOptions{
Text: "© Acme",
Position: "bottom-right",
Opacity: 60,
})
if err != nil {
log.Fatal(err)
}
if err := img.Save("photo-marked.jpg"); err != nil {
log.Fatal(err)
}
// …or a logo, here tiled across the photo.
_, err = client.Watermark(ctx, photos.File("photo.jpg"), &photos.WatermarkOptions{
Watermark: photos.File("logo.png"),
Scale: 15,
Tile: true,
})
if err != nil {
log.Fatal(err)
}
}
Output:
func (*Client) WebhookSecret ¶
func (c *Client) WebhookSecret(ctx context.Context) (*WebhookSecret, error)
WebhookSecret returns the key your job webhooks are signed with; pass its Secret to VerifyWebhook.
type ColorizeOptions ¶
type ColorizeOptions struct {
// Strength is how colourful the result is, 1–100: 100 (the default) is
// the model's colour as it is, lower is paler.
Strength float64
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
ColorizeOptions are the options of Colorize. Zero fields are not sent.
type ConnectionError ¶
type ConnectionError struct {
// Err is the cause, from net/http.
Err error
// Timeout is true when the Client's timeout (WithTimeout) passed, or the
// network reported a timeout. Timeouts are not retried.
Timeout bool
// contains filtered or unexported fields
}
ConnectionError means no (complete) response arrived: the connection could not be made or broke, or the Client's timeout passed. Unwrap gives the cause.
A cancelled context, or one whose own deadline passed, is not reported as a ConnectionError: the call returns context.Canceled or context.DeadlineExceeded.
func (*ConnectionError) Error ¶
func (e *ConnectionError) Error() string
func (*ConnectionError) Unwrap ¶
func (e *ConnectionError) Unwrap() error
type CropOptions ¶
type CropOptions struct {
// Aspect is the shape as width:height ("4:5", "16:9", "1:1") or a number
// ("1.5").
Aspect string
// Width and Height scale the crop to exactly this size in pixels; give
// both. Without Aspect they are the shape as well.
Width int
Height int
// Zoom crops tightly around the subject: the smallest window of the
// shape that holds it and its Padding. Without Zoom the crop is the
// largest window of the shape, moved to hold the subject.
Zoom bool
// Padding is the room around the subject with Zoom, as a fraction of
// its longest side, 0 to 2 (default 0.1). It is a pointer because 0 (no
// room) is a value: use Float.
Padding *float64
// Focus is what the crop is built around: "subject" (the default) or
// "face" (all the faces in the photo as one area). For a portrait or an
// avatar use "face" with Zoom and a Padding around 0.6.
Focus string
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
CropOptions are the options of Crop. Zero fields are not sent.
type DenoiseOptions ¶
type DenoiseOptions struct {
// Strength is how much of the cleaned result replaces the photo, 1–100:
// 100 (the default) is all of it, 50 half-way back to the original.
Strength float64
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
DenoiseOptions are the options of Denoise. Zero fields are not sent.
type EnhanceOptions ¶
type EnhanceOptions struct {
// Auto is automatic levels and white balance together. It is on when no
// other setting is given; Bool(true) keeps it beside other settings.
Auto *bool
// Levels stretches the tones so the darkest pixels are black and the
// brightest white. Nil follows Auto.
Levels *bool
// WhiteBalance takes out a colour cast. Nil follows Auto.
WhiteBalance *bool
// Brightness, Contrast and Saturation go from -100 to 100; zero changes
// nothing. A Saturation of -100 is black and white.
Brightness float64
Contrast float64
Saturation float64
// Temperature goes from -100 (cooler, bluer) to 100 (warmer).
Temperature float64
// Sharpen goes from 0 to 100.
Sharpen float64
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
EnhanceOptions are the options of Enhance. Without any, Enhance stretches the tones to the full range and takes out a colour cast. With any setting, only what is given is applied.
type EraseOptions ¶
type EraseOptions struct {
// Rects are the areas to remove.
Rects []Rect
// Mask is an image the size of the photo, white where to remove. The
// zero Input means no mask.
Mask Input
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
EraseOptions say what Erase removes: the areas in Rects, the white parts of Mask, or both. At least one is needed.
type Error ¶
type Error struct {
// Status is the HTTP status.
Status int
// Code is the API's error code (one of the Code constants; the API may
// add more). It is empty when the response was not the API's JSON, as
// from a proxy in front of it.
Code string
// Message says what went wrong. For a response that was not the API's
// JSON it is the start of the body.
Message string
// RetryAfter is the Retry-After header, zero when the response had none.
RetryAfter time.Duration
// Header is the response's headers.
Header http.Header
}
Error is an error response from the API. Get at it with errors.As, or test for one code with errors.Is and a sentinel:
if errors.Is(err, photos.ErrPaymentRequired) { … }
var apiErr *photos.Error
if errors.As(err, &apiErr) { log.Print(apiErr.Status, apiErr.Code) }
Example ¶
Errors from the API are *photos.Error values: branch on the code with errors.Is, or read the details with errors.As.
package main
import (
"context"
"errors"
"fmt"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
_, err := client.Upscale(context.Background(), photos.File("small.jpg"), nil)
var apiErr *photos.Error
var connErr *photos.ConnectionError
switch {
case err == nil:
// Use the image.
case errors.Is(err, photos.ErrPaymentRequired):
fmt.Println("out of credits")
case errors.Is(err, photos.ErrBusy):
// Already retried; apiErr.RetryAfter says when to try again.
fmt.Println("busy")
case errors.As(err, &apiErr):
fmt.Println(apiErr.Status, apiErr.Code, apiErr.Message)
case errors.As(err, &connErr):
fmt.Println("could not reach the API; timed out:", connErr.Timeout)
case errors.Is(err, context.DeadlineExceeded), errors.Is(err, context.Canceled):
fmt.Println("the context ended")
default:
fmt.Println(err) // a file that could not be read, for one
}
}
Output:
type Event ¶
type Event struct {
// Type is the kind of event: EventJobCompleted.
Type string `json:"type"`
// Job is the job the event is about.
Job *Job `json:"job,omitempty"`
// Raw is the event as it came.
Raw json.RawMessage `json:"-"`
}
Event is a verified webhook delivery.
func VerifyWebhook ¶
VerifyWebhook checks that a webhook delivery was signed by Photos.sh and returns the event it carries.
body is the request body exactly as received (verify before decoding it), header the value of the Photos-Signature header ("t=<unix seconds>,v1=<hex>"), and secret your signing key (Client.WebhookSecret). Deliveries whose timestamp is more than tolerance from now are rejected; a tolerance of zero or less means DefaultWebhookTolerance.
It needs no Client. An error is one of ErrWebhookHeader, ErrWebhookSignature, ErrWebhookTimestamp or ErrWebhookPayload.
Example ¶
A webhook endpoint: verify the delivery against the raw body before trusting it.
package main
import (
"io"
"log"
"net/http"
"os"
photos "github.com/photos-sh/photos-go"
)
func main() {
secret := os.Getenv("PHOTOS_WEBHOOK_SECRET") // from Client.WebhookSecret
http.HandleFunc("/hooks/photos", func(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(http.MaxBytesReader(w, r.Body, 1<<20))
if err != nil {
http.Error(w, "cannot read the body", http.StatusBadRequest)
return
}
event, err := photos.VerifyWebhook(body, r.Header.Get(photos.SignatureHeader), secret, 0)
if err != nil {
http.Error(w, "bad signature", http.StatusBadRequest)
return
}
if event.Type == photos.EventJobCompleted {
log.Printf("job %s: %d done, %d failed", event.Job.ID, event.Job.Counts.Done, event.Job.Counts.Failed)
}
w.WriteHeader(http.StatusNoContent)
})
}
Output:
func VerifyWebhookAt ¶
func VerifyWebhookAt(body []byte, header, secret string, tolerance time.Duration, now time.Time) (*Event, error)
VerifyWebhookAt is VerifyWebhook with the current time given as now, for tests and for verifying stored deliveries.
Example ¶
package main
import (
"errors"
"fmt"
"time"
photos "github.com/photos-sh/photos-go"
)
func main() {
body := []byte(`{"type":"job.completed","job":{"id":"job_1"}}`)
header := "t=1800000000,v1=90c1672761ea299dc1569349a086c9d9c3053d8fa0636d77d40a0286ce3fb226"
event, err := photos.VerifyWebhookAt(body, header, "whsec_test", 5*time.Minute, time.Unix(1800000060, 0))
fmt.Println(event.Type, event.Job.ID, err)
_, err = photos.VerifyWebhookAt(body, header, "whsec_test", 5*time.Minute, time.Unix(1800009999, 0))
fmt.Println(errors.Is(err, photos.ErrWebhookTimestamp))
_, err = photos.VerifyWebhookAt(body, header, "another secret", 5*time.Minute, time.Unix(1800000060, 0))
fmt.Println(err)
}
Output: job.completed job_1 <nil> true photos: webhook: signature does not match
type ExpandOptions ¶
type ExpandOptions struct {
// Aspect is the shape to reach, as width:height ("1:1") or a number. The
// photo stays in the centre.
Aspect string
// Left, Right, Top and Bottom are the pixels to add on each side. A side
// can grow by at most the photo's own width or height.
Left int
Right int
Top int
Bottom int
// Fill is "inpaint" (the default: the new area continues the photo) or a
// colour ("white", "black", "#rrggbb"), which needs no model.
Fill string
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
ExpandOptions say how Expand grows the canvas: to a shape (Aspect), or by pixels on each side, not both. Zero fields are not sent.
type Face ¶
type Face struct {
// Box runs from forehead to chin.
Box FaceBox `json:"box"`
// Landmarks are five points of the face.
Landmarks FaceLandmarks `json:"landmarks"`
// Score is how sure the model is that this is a face, 0–1.
Score float64 `json:"score"`
// Roll is the tilt of the line through the eyes, in degrees: 0 for a
// level head.
Roll float64 `json:"roll"`
}
Face is one face in a photo. Its coordinates are in the photo's pixels, after its EXIF rotation.
type FaceBox ¶
type FaceBox struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Width float64 `json:"width"`
Height float64 `json:"height"`
}
FaceBox is where a face is. It can reach past the photo's edges (a negative X or Y) for a face partly out of the frame.
type FaceLandmarks ¶
type FaceLandmarks struct {
RightEye Point `json:"right_eye"`
LeftEye Point `json:"left_eye"`
Nose Point `json:"nose"`
MouthRight Point `json:"mouth_right"`
MouthLeft Point `json:"mouth_left"`
}
FaceLandmarks are five points of a face. "Right" and "left" are the person's own, so RightEye is the one on the left of the photo.
type FacesResult ¶
type FacesResult struct {
// Width and Height are the photo's size in pixels, after its EXIF
// rotation.
Width int `json:"width"`
Height int `json:"height"`
// Faces are the faces found, the surest first; empty when there are
// none.
Faces []Face `json:"faces"`
// Raw is the response as it came.
Raw json.RawMessage `json:"-"`
}
FacesResult is what FindFaces returns.
func (*FacesResult) UnmarshalJSON ¶
func (r *FacesResult) UnmarshalJSON(data []byte) (err error)
UnmarshalJSON decodes the result and keeps the JSON in Raw.
type FindFacesOptions ¶
type FindFacesOptions struct {
// MinScore is how sure the model must be that something is a face,
// 0.1–1 (default 0.6).
MinScore float64
}
FindFacesOptions are the options of FindFaces. Zero fields are not sent.
type Finding ¶
type Finding struct {
// Code is a stable identifier: "blurry", "too_small",
// "background_not_white", "text_overlay"…
Code string `json:"code"`
// Severity is "info", "warning" or "error"; an error breaks a
// marketplace rule.
Severity string `json:"severity"`
Message string `json:"message"`
// Detail is what was measured or found, when there is something to say.
Detail string `json:"detail,omitempty"`
}
Finding is one thing a check found.
type FixResult ¶
type FixResult struct {
Image
// Passed reports whether the fixed image passes the marketplace's check
// (X-Marketplace-Passed).
Passed bool
// Findings are the codes of the findings still present
// (X-Marketplace-Findings); empty, never nil, when there are none.
Findings []string
}
FixResult is the image Fix returns, and the marketplace's verdict on it.
type FoundText ¶
type FoundText struct {
Text string `json:"text"`
// OnProduct says whether it is printed on the product; nil when the
// product was not looked for.
OnProduct *bool `json:"on_product"`
}
FoundText is a piece of text Check read in a photo.
type IDPhotoDocument ¶
type IDPhotoDocument struct {
// Name is what IDPhotoOptions.Document takes, such as "us-passport".
Name string `json:"name"`
Title string `json:"title"`
// Checked is the date (YYYY-MM-DD) the rules were last compared with
// the sources.
Checked string `json:"checked"`
// Sources are the official pages the rules were read from.
Sources []string `json:"sources"`
// Notes are rules the tool cannot check or make true.
Notes []string `json:"notes"`
// WidthMm and HeightMm are the photo's size in millimetres.
WidthMm float64 `json:"width_mm"`
HeightMm float64 `json:"height_mm"`
// HeadMinMm and HeadMaxMm are the smallest and largest allowed head,
// chin to crown, in millimetres.
HeadMinMm float64 `json:"head_min_mm"`
HeadMaxMm float64 `json:"head_max_mm"`
// EyesFromBottomMm is the smallest and the largest distance of the eyes
// from the bottom edge, for a document with such a rule; nil otherwise.
EyesFromBottomMm []float64 `json:"eyes_from_bottom_mm,omitempty"`
// Background is the background the rules ask for, as a colour.
Background string `json:"background"`
// Alteration is what the authority says about photos changed by
// software, in its own words; empty when it says nothing.
Alteration string `json:"alteration,omitempty"`
// Raw is the document as it came.
Raw json.RawMessage `json:"-"`
}
IDPhotoDocument is an identity document whose photo rules IDPhoto knows.
func (*IDPhotoDocument) UnmarshalJSON ¶
func (d *IDPhotoDocument) UnmarshalJSON(data []byte) (err error)
UnmarshalJSON decodes the document and keeps the JSON in Raw.
type IDPhotoOptions ¶
type IDPhotoOptions struct {
// Document names a document with built-in rules, such as "us-passport";
// IDPhotos lists them.
Document string
// WidthMm and HeightMm are the photo's size in millimetres, 10–200.
WidthMm float64
HeightMm float64
// HeadMinMm and HeadMaxMm are the smallest and largest allowed head,
// chin to crown, in millimetres.
HeadMinMm float64
HeadMaxMm float64
// EyesMinMm and EyesMaxMm are the eyes' allowed distance from the bottom
// edge, for documents with such a rule. Give both or neither.
EyesMinMm float64
EyesMaxMm float64
// DPI is the pixels per inch of the result, 100–1200 (default 300). It
// is also written into the file.
DPI int
// Background is "keep" (the default: the photo's own background),
// "document" (the colour the document asks for) or a colour ("white",
// "#rrggbb"). Anything but "keep" cuts the person out and replaces the
// background, and many authorities do not accept a photo changed that
// way.
Background string
// Format is the output format; the default is JPEG.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
IDPhotoOptions say what IDPhoto frames the portrait for: a Document, or the photo and head sizes (WidthMm, HeightMm, HeadMinMm and HeadMaxMm), not both. Zero fields are not sent.
type IDPhotoResult ¶
type IDPhotoResult struct {
Image
// Passed reports whether Findings is empty (X-Id-Photo-Passed). It is
// not an approval of the photo: expression, glasses, shadows, focus and
// likeness are not judged.
Passed bool
// Findings are the codes of what was found (X-Id-Photo-Findings):
// "head_tilted", "not_facing_camera", "head_cut_off", "not_enough_room",
// "low_resolution", "background_not_plain". Empty, never nil, when
// there are none.
Findings []string
// HeadMm is the head's height in the result, chin to crown, in
// millimetres (X-Id-Photo-Head-Mm).
HeadMm float64
}
IDPhotoResult is the photo IDPhoto returns, and what the tool could see is wrong with it.
type IdentifyLabel ¶
type IdentifyLabel struct {
Ages []int `json:"ages,omitempty"`
WeakAges []int `json:"weak_ages,omitempty"`
Years []int `json:"years,omitempty"`
ABVs []float64 `json:"abvs,omitempty"`
// Sizes are in centilitres.
Sizes []float64 `json:"sizes,omitempty"`
// Quantities are net quantities, in "g" or "ml".
Quantities []Measure `json:"quantities,omitempty"`
// Packs are the units in a multipack: 6 for "6 x 330 ml".
Packs []int `json:"packs,omitempty"`
// SPFs are sun protection factors.
SPFs []int `json:"spfs,omitempty"`
// Strengths are those of a medicine or supplement, in "mg", "iu" or
// "percent".
Strengths []Measure `json:"strengths,omitempty"`
// Counts are the tablets, capsules, washes, rolls, wipes, batteries and
// the like in the pack.
Counts []int `json:"counts,omitempty"`
// Specs are technical values, in "gb", "mah", "wh", "w", "v", "a", "hz"
// or "in".
Specs []Measure `json:"specs,omitempty"`
}
IdentifyLabel is what Identify read off the label; which values there are depends on the catalogue's kind.
type IdentifyOptions ¶
type IdentifyOptions struct {
// Catalogue names the catalogue to search; it may be empty when your
// organisation has exactly one.
Catalogue string
// Top is how many candidates to return, 1–50 (default 5).
Top int
}
IdentifyOptions are the options of Identify. Zero fields are not sent.
type IdentifyResult ¶
type IdentifyResult struct {
Catalogue string `json:"catalogue"`
// Candidates are the products that match, best first.
Candidates []Candidate `json:"candidates"`
// Label is what was read off the label.
Label IdentifyLabel `json:"label"`
// Barcodes are the codes read.
Barcodes []string `json:"barcodes"`
// Text is all the text recognised.
Text string `json:"text,omitempty"`
// Ms is how long each step took, in milliseconds.
Ms map[string]int64 `json:"ms,omitempty"`
// Raw is the response as it came.
Raw json.RawMessage `json:"-"`
}
IdentifyResult is what Identify returns.
func (*IdentifyResult) UnmarshalJSON ¶
func (r *IdentifyResult) UnmarshalJSON(data []byte) (err error)
UnmarshalJSON decodes the result and keeps the JSON in Raw.
type Image ¶
type Image struct {
// Bytes is the encoded image.
Bytes []byte
// ContentType is its media type, such as "image/png".
ContentType string
// Width and Height are its size in pixels (the X-Image-Width and
// X-Image-Height headers), zero if the response did not say.
Width int
Height int
// Quality is the quality it was encoded at, 1–100 (X-Image-Quality).
// It is zero for formats without one, such as PNG.
Quality int
// ServerTiming is the raw Server-Timing header: how long each step took.
ServerTiming string
// SubjectFound says whether a subject was found in the photo (the
// X-Subject-Found header). It is nil when the response did not say: nil
// means "unknown", not "no". Crop always says. RemoveBackground says
// false when a canvas was asked for and the photo has no subject; the
// canvas is then empty.
SubjectFound *bool
// Header is every header of the response.
Header http.Header
}
Image is an image the API returned.
type Input ¶
type Input struct {
// contains filtered or unexported fields
}
Input is an image to send: make one with File, Bytes or Reader. The zero Input is "no image".
The request body is streamed, not built in memory, so a large file costs no more memory than a small one.
Retries need the body a second time. File and Bytes inputs can always be sent again. A Reader input can be sent again only if it is also an io.Seeker (an *os.File, a *bytes.Reader); a request with any other reader is sent once and never retried, whatever WithRetries says: the first answer, such as a 503 "busy" *Error, is returned as it is. Read the data into memory and use Bytes when you want such a stream retried.
func Bytes ¶
Bytes is an image held in memory. name is the file name the API sees (job items are listed under it); it may be empty.
func File ¶
File is the image in the file at path. The file is opened when the request is sent, and again for each retry.
type ItemError ¶
ItemError is why a job item failed: the error the synchronous endpoint would have answered with.
func (*ItemError) UnmarshalJSON ¶
UnmarshalJSON accepts the usual {"code", "message"} object, and a bare string as the message.
type Job ¶
type Job struct {
ID string `json:"id"`
Operation string `json:"operation"`
// Params is the operation's parameters as a query string.
Params string `json:"params"`
// Status is JobQueued, JobRunning or JobCompleted.
Status string `json:"status"`
// CreatedAt and FinishedAt are Unix seconds; FinishedAt is zero until
// the job has completed.
CreatedAt int64 `json:"created_at"`
FinishedAt int64 `json:"finished_at,omitempty"`
Counts JobCounts `json:"counts"`
Items []JobItem `json:"items"`
// Webhook is the state of the webhook delivery, when the job has one.
Webhook *JobWebhook `json:"webhook,omitempty"`
// Raw is the job as it came.
Raw json.RawMessage `json:"-"`
}
Job is a batch job: its status, progress and per-item results.
func (*Job) UnmarshalJSON ¶
UnmarshalJSON decodes the job and keeps the JSON in Raw.
type JobCounts ¶
type JobCounts struct {
Total int `json:"total"`
Done int `json:"done"`
Failed int `json:"failed"`
Pending int `json:"pending"`
}
JobCounts counts a job's items by status.
type JobItem ¶
type JobItem struct {
// Input is the upload's file name, or the input URL.
Input string `json:"input"`
// URL is the input URL, for an input that was one.
URL string `json:"url,omitempty"`
// Status is ItemPending, ItemDone or ItemFailed.
Status string `json:"status"`
// Result is the path of the result when done; fetch it with Jobs.Item.
Result string `json:"result,omitempty"`
ContentType string `json:"content_type,omitempty"`
// Bytes is the size of the result.
Bytes int64 `json:"bytes,omitempty"`
// Headers are the result's headers, in lower case: x-image-width,
// x-image-height, x-image-quality and server-timing, plus
// x-text-removed and x-text-kept for a "remove-text" job,
// x-marketplace-passed and x-marketplace-findings for a "fix" job, and
// likewise x-subject-found, x-paths, x-faces, x-faces-skipped,
// x-select-score and x-id-photo-* for the operations that report them.
// (Older engines keep only the first four.)
// Jobs.Item returns the same headers with the result, and its
// RemoveText, Fix, RemoveBackground, Crop, Vectorize, BlurFaces,
// IDPhoto, Select and RestoreFaces read them for you.
Headers map[string]string `json:"headers,omitempty"`
// Error says why a failed item failed: an error code of the API, or
// CodeInputUnavailable when the input URL could not be fetched.
Error *ItemError `json:"error,omitempty"`
}
JobItem is one input of a job and what became of it.
type JobItemResult ¶
type JobItemResult struct {
// Body is the raw result: an encoded image, or JSON.
Body []byte
// ContentType is its media type.
ContentType string
// Header is every header of the response.
Header http.Header
// contains filtered or unexported fields
}
JobItemResult is the result of one finished item: what the synchronous endpoint would have returned.
func (*JobItemResult) BlurFaces ¶
func (r *JobItemResult) BlurFaces() (*BlurFacesResult, error)
BlurFaces returns the result of a "blur-faces" job's item as the synchronous Client.BlurFaces would: the image and how many faces were hidden. Without the X-Faces header it returns an ErrMissingResultHeaders, as RemoveText does.
func (*JobItemResult) Crop ¶
func (r *JobItemResult) Crop() (*Image, error)
Crop returns the result of a "crop" job's item as the synchronous Client.Crop would: the image, whose SubjectFound says whether a subject was found. Without the X-Subject-Found header, which a crop always carries, it returns an ErrMissingResultHeaders, as RemoveText does.
func (*JobItemResult) Fix ¶
func (r *JobItemResult) Fix() (*FixResult, error)
Fix returns the result of a "fix" job's item as the synchronous Client.Fix would: the image, whether it passes the marketplace's check, and the findings still present.
If the result does not carry the X-Marketplace-Passed header (it belongs to another operation, or the engine is too old to keep the header on job items), Fix returns no result and an error for which errors.Is(err, ErrMissingResultHeaders) is true, rather than a false verdict. Image still gives the image.
Example ¶
The items of a "fix" job carry the marketplace's verdict, as Client.Fix returns it; those of a "remove-text" job have RemoveText likewise.
package main
import (
"context"
"errors"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
ctx := context.Background()
job, err := client.Jobs.Create(ctx, &photos.JobRequest{
Operation: photos.OperationFix,
Params: map[string]any{"marketplace": "etsy"},
Images: []photos.Input{photos.File("1.jpg"), photos.File("2.jpg")},
})
if err != nil {
log.Fatal(err)
}
if job, err = client.Jobs.Wait(ctx, job.ID, nil); err != nil {
log.Fatal(err)
}
for n, item := range job.Items {
if item.Status != photos.ItemDone {
continue
}
res, err := client.Jobs.Item(ctx, job.ID, n)
if err != nil {
log.Fatal(err)
}
fix, err := res.Fix()
if errors.Is(err, photos.ErrMissingResultHeaders) {
log.Fatal("this engine does not keep the verdict on job items")
} else if err != nil {
log.Fatal(err)
}
fmt.Println(item.Input, fix.Passed, fix.Findings)
if err := fix.Save(fmt.Sprintf("fixed-%d%s", n, fix.Extension())); err != nil {
log.Fatal(err)
}
}
}
Output:
func (*JobItemResult) IDPhoto ¶
func (r *JobItemResult) IDPhoto() (*IDPhotoResult, error)
IDPhoto returns the result of an "id-photo" job's item as the synchronous Client.IDPhoto would: the photo, the findings and the head's size. Without the X-Id-Photo-Passed header it returns an ErrMissingResultHeaders, as RemoveText does.
func (*JobItemResult) Image ¶
func (r *JobItemResult) Image() *Image
Image returns the result as an Image, with its size, quality, timing and SubjectFound (a "crop" or "remove-background" job) read from the headers, or nil if the result is not an image. The SVG of a "vectorize" job is one.
func (*JobItemResult) IsImage ¶
func (r *JobItemResult) IsImage() bool
IsImage reports whether the result is an image.
func (*JobItemResult) IsJSON ¶
func (r *JobItemResult) IsJSON() bool
IsJSON reports whether the result is JSON.
func (*JobItemResult) JSON ¶
func (r *JobItemResult) JSON(v any) error
JSON decodes a JSON result into v: a *CheckResult for a "check" job, a *TextResult for "ocr", a *BarcodesResult for "barcodes", a *LabelResult for "label", a *PaletteResult for "palette", a *FacesResult for "faces", a *CaptionResult for "caption", or any type of your own.
func (*JobItemResult) RemoveBackground ¶
func (r *JobItemResult) RemoveBackground() (*Image, error)
RemoveBackground returns the result of a "remove-background" job's item as the synchronous Client.RemoveBackground would: the image, whose SubjectFound is false when a canvas was asked for and the photo has no subject.
The API sends the X-Subject-Found header only then. A result without it is not an error: its SubjectFound is nil, which means "not known". A result that is not an image is an ErrMissingResultHeaders.
func (*JobItemResult) RemoveText ¶
func (r *JobItemResult) RemoveText() (*RemoveTextResult, error)
RemoveText returns the result of a "remove-text" job's item as the synchronous Client.RemoveText would: the image, and how many lines of text were removed and kept.
If the result does not carry the X-Text-Removed header (it belongs to another operation, or the engine is too old to keep the header on job items), RemoveText returns no result and an error for which errors.Is(err, ErrMissingResultHeaders) is true, rather than zero counts. Image still gives the image.
func (*JobItemResult) RestoreFaces ¶
func (r *JobItemResult) RestoreFaces() (*RestoreFacesResult, error)
RestoreFaces returns the result of a "restore-faces" job's item as the synchronous Client.RestoreFaces would: the image, and how many faces were restored and skipped. Without the X-Faces-Skipped header it returns an ErrMissingResultHeaders, as RemoveText does.
func (*JobItemResult) Select ¶
func (r *JobItemResult) Select() (*SelectResult, error)
Select returns the result of a "select" job's item as the synchronous Client.Select would: the cutout or the mask, and the model's score. Without the X-Select-Score header it returns an ErrMissingResultHeaders, as RemoveText does.
func (*JobItemResult) Vectorize ¶
func (r *JobItemResult) Vectorize() (*VectorizeResult, error)
Vectorize returns the result of a "vectorize" job's item as the synchronous Client.Vectorize would: the SVG and how many paths it has. Without the X-Paths header it returns an ErrMissingResultHeaders, as RemoveText does.
type JobRequest ¶
type JobRequest struct {
// Operation is the operation to run: one of the Operation constants.
Operation string
// Params are the operation's parameters, named as in the HTTP API:
// {"format": "png", "crop": true}. Values may be strings, booleans and
// numbers, and a []string for a parameter that repeats, such as the
// "point" of a "select" job.
//
// An item is one image, so a "watermark" job takes "text" only and a
// "remove-background" job no background image.
Params map[string]any
// Recipe is a recipe as TOML text, for OperationRun.
Recipe string
// URLs are images for the API to fetch: http(s) on public addresses.
URLs []string
// Images are images to upload. With none, the job is sent as JSON; with
// any, as multipart/form-data, streamed like any other upload.
Images []Input
// WebhookURL, if set, receives a signed "job.completed" event when the
// job is done; see VerifyWebhook.
WebhookURL string
}
JobRequest describes a new job: one operation applied to every input.
type JobSummary ¶
type JobSummary struct {
ID string `json:"id"`
Operation string `json:"operation"`
Status string `json:"status"`
// CreatedAt and FinishedAt are Unix seconds; FinishedAt is zero until
// the job has completed.
CreatedAt int64 `json:"created_at"`
FinishedAt int64 `json:"finished_at"`
Counts JobCounts `json:"counts"`
}
JobSummary is a job as Jobs.List shows it: without its items.
type JobWebhook ¶
type JobWebhook struct {
URL string `json:"url"`
Attempts int `json:"attempts"`
Delivered bool `json:"delivered"`
LastError string `json:"last_error,omitempty"`
}
JobWebhook is the state of a job's webhook delivery.
type JobsService ¶
type JobsService struct {
// contains filtered or unexported fields
}
JobsService runs one operation on many images in the background. Use it through Client.Jobs.
func (*JobsService) Create ¶
func (s *JobsService) Create(ctx context.Context, req *JobRequest) (*Job, error)
Create starts a job and returns at once; follow it with Get or Wait, or give a WebhookURL.
Unlike other calls, Create is sent again only after a 503: after a connection failure the job may already exist.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
ctx := context.Background()
// Images the API fetches…
job, err := client.Jobs.Create(ctx, &photos.JobRequest{
Operation: photos.OperationRemoveBackground,
Params: map[string]any{"format": "png", "crop": true},
URLs: []string{"https://example.com/photos/1.jpg", "https://example.com/photos/2.jpg"},
WebhookURL: "https://example.com/hooks/photos",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(job.ID, job.Status)
// …or images you upload.
job, err = client.Jobs.Create(ctx, &photos.JobRequest{
Operation: photos.OperationRun,
Params: map[string]any{"preset": "marketplace"},
Images: []photos.Input{photos.File("1.jpg"), photos.File("2.jpg")},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(job.ID, job.Counts.Total)
}
Output:
func (*JobsService) Delete ¶
func (s *JobsService) Delete(ctx context.Context, id string) error
Delete cancels a job if it is unfinished, and deletes it and its results.
func (*JobsService) Item ¶
func (s *JobsService) Item(ctx context.Context, id string, n int) (*JobItemResult, error)
Item returns the result of item n (from 0) of a job, once that item is done.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
// The result of an "ocr" job's first item is JSON.
res, err := client.Jobs.Item(context.Background(), "job_5f0c", 0)
if err != nil {
log.Fatal(err)
}
var text photos.TextResult
if err := res.JSON(&text); err != nil {
log.Fatal(err)
}
fmt.Println(len(text.Lines), "lines")
}
Output:
func (*JobsService) List ¶
func (s *JobsService) List(ctx context.Context) ([]JobSummary, error)
List returns your recent jobs, newest first (up to 100), without their items.
Example ¶
package main
import (
"context"
"fmt"
"log"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
ctx := context.Background()
jobs, err := client.Jobs.List(ctx)
if err != nil {
log.Fatal(err)
}
for _, j := range jobs {
fmt.Println(j.ID, j.Operation, j.Status, j.Counts.Done, "/", j.Counts.Total)
if j.Status == photos.JobCompleted {
if err := client.Jobs.Delete(ctx, j.ID); err != nil {
log.Fatal(err)
}
}
}
}
Output:
func (*JobsService) Wait ¶
func (s *JobsService) Wait(ctx context.Context, id string, opts *WaitOptions) (*Job, error)
Wait polls a job until it has completed and returns it. opts may be nil.
If the job has not completed within opts.Timeout, Wait returns the job as last seen and an error for which errors.Is(err, ErrWaitTimeout) is true. If ctx ends first, it returns ctx's error.
Example ¶
package main
import (
"context"
"errors"
"fmt"
"log"
"time"
photos "github.com/photos-sh/photos-go"
)
func main() {
client, _ := photos.New("")
ctx := context.Background()
job, err := client.Jobs.Wait(ctx, "job_5f0c", &photos.WaitOptions{
Interval: 5 * time.Second,
Timeout: 30 * time.Minute,
})
if errors.Is(err, photos.ErrWaitTimeout) {
log.Fatalf("still %s: %d of %d done", job.Status, job.Counts.Done, job.Counts.Total)
} else if err != nil {
log.Fatal(err)
}
for n, item := range job.Items {
if item.Status != photos.ItemDone {
fmt.Println(item.Input, "failed:", item.Error)
continue
}
res, err := client.Jobs.Item(ctx, job.ID, n)
if err != nil {
log.Fatal(err)
}
if img := res.Image(); img != nil {
if err := img.Save(fmt.Sprintf("result-%d%s", n, img.Extension())); err != nil {
log.Fatal(err)
}
}
}
}
Output:
type LabelAlcohol ¶
type LabelAlcohol struct {
// ABV is alcohol by volume, in percent.
ABV float64 `json:"abv"`
Text string `json:"text,omitempty"`
}
LabelAlcohol is an alcohol statement.
type LabelDate ¶
type LabelDate struct {
// Kind is "best_before", "use_by", "expiry", "production" or "packed".
Kind string `json:"kind"`
// Date is an ISO date or month, when it could be read.
Date string `json:"date,omitempty"`
Text string `json:"text,omitempty"`
}
LabelDate is a date printed on a label.
type LabelDetails ¶
type LabelDetails struct {
// Headline is the largest text: brand and product name candidates.
Headline []string `json:"headline,omitempty"`
GTIN string `json:"gtin,omitempty"`
GS1 *LabelGS1 `json:"gs1,omitempty"`
NetQuantity *LabelQuantity `json:"net_quantity,omitempty"`
Alcohol *LabelAlcohol `json:"alcohol,omitempty"`
AgeYears *int `json:"age_years,omitempty"`
Vintage *int `json:"vintage,omitempty"`
Bottled *int `json:"bottled,omitempty"`
Dates []LabelDate `json:"dates,omitempty"`
Lot string `json:"lot,omitempty"`
Serial string `json:"serial,omitempty"`
Model string `json:"model,omitempty"`
Ingredients string `json:"ingredients,omitempty"`
Allergens []string `json:"allergens,omitempty"`
MayContain []string `json:"may_contain,omitempty"`
Nutrition *LabelNutrition `json:"nutrition,omitempty"`
Materials []LabelMaterial `json:"materials,omitempty"`
Origin string `json:"origin,omitempty"`
Electrical *LabelElectric `json:"electrical,omitempty"`
// Claims are among "organic", "vegan", "vegetarian", "gluten_free",
// "lactose_free", "no_added_sugar", "sugar_free", "non_gmo",
// "fairtrade", "kosher", "halal".
Claims []string `json:"claims,omitempty"`
}
LabelDetails are the details read off a product's label. A field that was not found is its zero value: an empty string, a nil slice or a nil pointer.
type LabelElectric ¶
type LabelElectric struct {
Voltage string `json:"voltage,omitempty"`
Frequency string `json:"frequency,omitempty"`
PowerW *float64 `json:"power_w,omitempty"`
BatteryMAh *float64 `json:"battery_mah,omitempty"`
}
LabelElectric is the electrical rating of a device.
type LabelGS1 ¶
type LabelGS1 struct {
GTIN string `json:"gtin,omitempty"`
Batch string `json:"batch,omitempty"`
Serial string `json:"serial,omitempty"`
Expiry string `json:"expiry,omitempty"`
BestBefore string `json:"best_before,omitempty"`
Production string `json:"production,omitempty"`
Packed string `json:"packed,omitempty"`
NetWeightKg *float64 `json:"net_weight_kg,omitempty"`
Count *int `json:"count,omitempty"`
}
LabelGS1 is the content of a GS1 code (GS1-128, GS1 DataMatrix).
type LabelMaterial ¶
LabelMaterial is one material of a textile composition.
type LabelNutrition ¶
type LabelNutrition struct {
// Per is the reference amount, such as "100g" or "100ml".
Per string `json:"per,omitempty"`
EnergyKJ *float64 `json:"energy_kj,omitempty"`
EnergyKcal *float64 `json:"energy_kcal,omitempty"`
Fat *float64 `json:"fat,omitempty"`
Saturates *float64 `json:"saturates,omitempty"`
Carbohydrate *float64 `json:"carbohydrate,omitempty"`
Sugars *float64 `json:"sugars,omitempty"`
Fibre *float64 `json:"fibre,omitempty"`
Protein *float64 `json:"protein,omitempty"`
Salt *float64 `json:"salt,omitempty"`
}
LabelNutrition is a nutrition table; values not printed are nil.
type LabelQuantity ¶
type LabelQuantity struct {
Value float64 `json:"value"`
// Unit is "ml", "cl", "dl", "l", "fl_oz", "g", "kg", "oz" or "lb".
Unit string `json:"unit"`
Ml *float64 `json:"ml,omitempty"`
Grams *float64 `json:"grams,omitempty"`
// Count is the number of items in a multipack.
Count *int `json:"count,omitempty"`
Text string `json:"text,omitempty"`
}
LabelQuantity is a net quantity, such as "70 cl" or "6 × 330 ml".
type LabelResult ¶
type LabelResult struct {
// Label is what was understood; fields not found are left zero.
Label LabelDetails `json:"label"`
// Barcodes are the codes found, as the API gives them.
Barcodes []map[string]any `json:"barcodes"`
// Text is every line read.
Text []string `json:"text"`
// Ms is how long each step took, in milliseconds.
Ms map[string]int64 `json:"ms,omitempty"`
// Raw is the response as it came.
Raw json.RawMessage `json:"-"`
}
LabelResult is what ReadLabel returns.
func (*LabelResult) UnmarshalJSON ¶
func (r *LabelResult) UnmarshalJSON(data []byte) (err error)
UnmarshalJSON decodes the result and keeps the JSON in Raw.
type Marketplace ¶
type Marketplace struct {
Name string `json:"name"`
Title string `json:"title"`
// Checked is the date (YYYY-MM-DD) the rules were last checked against
// the sources.
Checked string `json:"checked"`
Sources []string `json:"sources"`
// Notes are rules that cannot be checked automatically.
Notes []string `json:"notes,omitempty"`
// Rules are the rules as the API gives them; each has at least "check"
// and "severity".
Rules []map[string]any `json:"rules"`
// Fix is what Fix produces for this marketplace.
Fix map[string]any `json:"fix"`
// Raw is the marketplace as it came.
Raw json.RawMessage `json:"-"`
}
Marketplace is a marketplace's image rules.
func (*Marketplace) UnmarshalJSON ¶
func (m *Marketplace) UnmarshalJSON(data []byte) (err error)
UnmarshalJSON decodes the marketplace and keeps the JSON in Raw.
type Metrics ¶
type Metrics struct {
Width int `json:"width"`
Height int `json:"height"`
// Sharpness is edge crispness; under 0.3 is blurry, under 0.5 soft.
Sharpness float64 `json:"sharpness"`
// Noise is in grey levels (above 4 is visible grain); nil when it could
// not be measured.
Noise *float64 `json:"noise"`
Brightness float64 `json:"brightness"`
HighlightsClipped float64 `json:"highlights_clipped"`
ShadowsClipped float64 `json:"shadows_clipped"`
Brightest float64 `json:"brightest"`
Border Border `json:"border"`
// Subject is the product, when it was looked for and found.
Subject *Subject `json:"subject"`
}
Metrics are the measurements of a photo.
type Option ¶
Option changes how New builds a Client.
func WithBaseURL ¶
WithBaseURL sets the address of the API, for example "http://localhost:8080". A trailing slash is ignored. It takes precedence over the PHOTOS_BASE_URL environment variable.
func WithHTTPClient ¶
WithHTTPClient makes the Client send its requests with hc (for a proxy, a custom transport, or tracing). The Client's own timeout still applies to every attempt; see WithTimeout.
func WithRetries ¶
WithRetries sets how many times a request is sent again after a 503 response or a connection failure (default DefaultRetries). Zero turns retries off.
func WithTimeout ¶
WithTimeout sets how long one HTTP attempt may take, from sending the request to reading the last byte of the response. The default is DefaultTimeout (120 s; model work takes seconds). Zero means no timeout beyond the context's own deadline.
func WithUserAgent ¶
WithUserAgent puts a product token for your application in front of the library's own, giving "<userAgent> photos-sh-go/<version>".
type PaletteColor ¶
type PaletteColor struct {
// Hex is the colour as "#rrggbb".
Hex string `json:"hex"`
// RGB is its red, green and blue, each 0–255.
RGB []int `json:"rgb"`
// 0–1.
Share float64 `json:"share"`
}
PaletteColor is one colour of a palette.
type PaletteOptions ¶
type PaletteOptions struct {
// Colors is how many colours to return at most, 1–16 (default 5).
Colors int
}
PaletteOptions are the options of Palette. Zero fields are not sent.
type PaletteResult ¶
type PaletteResult struct {
// Width and Height are the image's size in pixels.
Width int `json:"width"`
Height int `json:"height"`
// Colors are the image's main colours, the most common first.
Colors []PaletteColor `json:"colors"`
// Raw is the response as it came.
Raw json.RawMessage `json:"-"`
}
PaletteResult is what Palette returns.
func (*PaletteResult) UnmarshalJSON ¶
func (r *PaletteResult) UnmarshalJSON(data []byte) (err error)
UnmarshalJSON decodes the result and keeps the JSON in Raw.
type Point ¶
type Point struct {
X, Y float64
}
Point is a position in an image in pixels, from its top-left corner. In JSON it is an [x, y] pair.
func (Point) MarshalJSON ¶
MarshalJSON encodes the point as [x, y].
func (*Point) UnmarshalJSON ¶
UnmarshalJSON decodes the point from [x, y].
type ReadBarcodesOptions ¶
type ReadBarcodesOptions struct {
// AllFormats adds EAN-8, UPC-E, Code 128/39/93, QR, Data Matrix and
// PDF417 to the retail codes read by default.
AllFormats bool
// Engine is "auto" (default), "zbar" or "rxing".
Engine string
}
ReadBarcodesOptions are the options of ReadBarcodes. Zero fields are not sent.
type Rect ¶
type Rect struct {
X, Y, Width, Height int
}
Rect is an area of an image in pixels, from its top-left corner.
type RemoveBackgroundOptions ¶
type RemoveBackgroundOptions struct {
// Format is the output format: "png" (the default), "jpg", "webp" or "avif".
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
// Background composites the cutout onto a colour ("white", "#rrggbb").
// Empty keeps it transparent (JPEG output defaults to white).
Background string
// Crop crops to the subject.
Crop bool
// Padding is the margin around the subject when cropping, in pixels.
Padding int
// Mask returns the greyscale alpha mask instead of the cutout.
Mask bool
// Width and Height place the subject on a canvas of this size, in
// pixels. Give both. Without them the photo keeps its size.
Width int
Height int
// Fill is how much of the canvas the subject may take in its tighter
// dimension, 0.05 to 1 (default 0.85). It needs Width and Height.
Fill float64
// Align is where the subject sits on the canvas: "center" (the
// default), "top" (hanging from the top margin) or "bottom" (standing on
// the bottom margin).
Align string
// Shadow is "contact" (a soft shadow at the subject's base, as if it
// stands on a surface), "drop" (the silhouette, offset and blurred) or
// "none" (the default).
Shadow string
// Reflection adds a fading mirror image under the subject. Leave room
// below it: a canvas with Fill under 1.
Reflection bool
// Blur keeps the photo's own background behind the subject, blurred:
// 1 (slight) to 100.
Blur float64
// BackgroundImage is an image to put behind the subject; it is scaled to
// cover the result. The zero Input means none.
BackgroundImage Input
}
RemoveBackgroundOptions are the options of RemoveBackground. Zero fields are not sent.
The fields after Mask stage the cutout in the same call: a canvas with the subject at a set size and position, a shadow or a reflection under it, and something behind it. Give at most one of Background, BackgroundImage and Blur. Mask takes none of them, and Crop goes with neither a canvas nor Blur.
type RemoveTextOptions ¶
type RemoveTextOptions struct {
// Region is RegionBackground (default: only text off the product) or
// RegionAll.
Region string
// Matching limits removal to lines matching this case-insensitive
// regular expression, such as `sale|€|www\.`.
Matching string
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
RemoveTextOptions are the options of RemoveText. Zero fields are not sent.
type RemoveTextResult ¶
type RemoveTextResult struct {
Image
// Removed is how many lines of text were painted out (X-Text-Removed).
Removed int
// Kept is how many were left in place (X-Text-Kept).
Kept int
}
RemoveTextResult is the image RemoveText returns, and what it did.
type ResizeOptions ¶
type ResizeOptions struct {
// Width and Height are the target size in pixels. Give one to keep the
// proportions, or both.
Width int
Height int
// Fit says how to fit when both sides are given: FitContain (default),
// FitCover or FitFill. Cover and fill need both sides.
Fit string
// Enlarge allows scaling up with FitContain.
Enlarge bool
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100 (WebP 100 is lossless).
Quality int
// MaxBytes lowers the quality until the file fits in this many bytes.
MaxBytes int
// Background flattens transparency onto this colour.
Background string
// Trim cuts away an even border first: whatever matches the top-left
// pixel, or is transparent like it.
Trim bool
// TrimTolerance is how far a pixel may differ from the border's colour
// and still be border, per channel, 0–255 (default 10). It needs Trim.
// It is a pointer because 0 (only the exact colour) is a value: use Int.
TrimTolerance *int
// DPI is the print resolution to write into a JPEG or PNG, 1–2400. No
// pixel changes; WebP and AVIF have no such field.
DPI int
}
ResizeOptions are the options of Resize. Zero fields are not sent.
type RestoreFacesOptions ¶
type RestoreFacesOptions struct {
// Strength is how much of the restored face replaces the original,
// 1–100 (default 100: all of it).
Strength float64
// MinScore is how sure the detector must be that something is a face,
// 0.1–1 (default 0.6).
MinScore float64
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
RestoreFacesOptions are the options of RestoreFaces. Zero fields are not sent.
type RestoreFacesResult ¶
type RestoreFacesResult struct {
Image
// Faces is how many faces were restored (X-Faces).
Faces int
// FacesSkipped is how many were left alone because they are large and
// detailed enough already (X-Faces-Skipped).
FacesSkipped int
}
RestoreFacesResult is the image RestoreFaces returns, and what it did.
type RunOptions ¶
type RunOptions struct {
// Preset is the name of a built-in preset, such as "marketplace".
Preset string
// Recipe is a recipe as TOML text.
Recipe string
}
RunOptions name what Run applies: a built-in preset (see Presets) or a recipe.
type SelectOptions ¶
type SelectOptions struct {
// Points are points on the object. More than one adds to the selection.
Points []Point
// Exclude are points that must stay outside the selection.
Exclude []Point
// Box is a box around the object. The zero Rect means none.
Box Rect
// Pick says which of the model's three answers to return: "auto" (the
// default: the surest one that agrees with every point), "smallest" (the
// part clicked) or "largest" (the whole thing it belongs to).
Pick string
// Mask returns the greyscale mask instead of the cutout. Erase takes it
// as its Mask, to remove the object.
Mask bool
// Crop crops to the object.
Crop bool
// Padding is the margin around the object when cropping, in pixels.
Padding int
// Background composites the cutout onto a colour ("white", "#rrggbb").
// Empty keeps it transparent (JPEG output defaults to white).
Background string
// Format is the output format: "png" (the default), "jpg", "webp" or "avif".
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
SelectOptions say which object Select cuts out: the one at Points, or in Box. At least one point or a box is needed. Coordinates are in the photo's pixels, after its EXIF rotation.
type SelectResult ¶
type SelectResult struct {
Image
// Score is how well the model thinks the mask fits the object, 0 to 1
// (X-Select-Score).
Score float64
}
SelectResult is the cutout (or the mask) Select returns, and how sure the model is of it.
type Subject ¶
type Subject struct {
X int `json:"x"`
Y int `json:"y"`
Width int `json:"width"`
Height int `json:"height"`
// Fill is the share of the frame the product spans.
Fill float64 `json:"fill"`
Area float64 `json:"area"`
// Touches lists the edges the product touches: "top", "bottom", "left",
// "right".
Touches []string `json:"touches"`
BackgroundWhite float64 `json:"background_white"`
}
Subject is where the product is in a photo.
type TextLine ¶
type TextLine struct {
Text string `json:"text"`
// Score is the mean character confidence, 0–1.
Score float64 `json:"score"`
// Box is the line's corners in pixels (x, y), clockwise from the
// top-left.
Box [][]float64 `json:"box"`
}
TextLine is one line of text in a photo.
type TextResult ¶
type TextResult struct {
// Lines are the lines of text, top to bottom.
Lines []TextLine `json:"lines"`
// Ms is how long each step took, in milliseconds.
Ms map[string]int64 `json:"ms,omitempty"`
// Raw is the response as it came.
Raw json.RawMessage `json:"-"`
}
TextResult is what ReadText returns.
func (*TextResult) UnmarshalJSON ¶
func (r *TextResult) UnmarshalJSON(data []byte) (err error)
UnmarshalJSON decodes the result and keeps the JSON in Raw.
type UpscaleOptions ¶
type UpscaleOptions struct {
// Scale is the factor, 1 to 4 (default 4).
Scale float64
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
UpscaleOptions are the options of Upscale. Zero fields are not sent.
type VectorizeOptions ¶
type VectorizeOptions struct {
// Mode is "color" (the default) or "mono", which draws whatever is
// darker than mid grey as one black shape.
Mode string
// Curves is "spline" (smooth curves, the default), "polygon" (straight
// segments) or "pixel" (every pixel step, for pixel art).
Curves string
// Detail is the bits kept per colour channel when grouping pixels, 1–8
// (default 8). Lower merges similar shades into fewer shapes.
Detail int
// Speckle drops areas smaller than this many pixels across, 0–100
// (default 4). It is a pointer because 0 (keep everything) is a value:
// use Int.
Speckle *int
}
VectorizeOptions are the options of Vectorize. Zero fields are not sent.
type VectorizeResult ¶
VectorizeResult is the SVG Vectorize returns. Bytes is the SVG's text and ContentType "image/svg+xml"; Width and Height are the size the image was traced at.
type Verdict ¶
type Verdict struct {
Marketplace string `json:"marketplace"`
Title string `json:"title,omitempty"`
// Passed is true when no "error" rule is broken and every one was
// checked.
Passed bool `json:"passed"`
Findings []Finding `json:"findings"`
// NotChecked are the rules that could not be checked.
NotChecked []string `json:"not_checked"`
// Notes are rules for the seller to check by eye.
Notes []string `json:"notes,omitempty"`
Checked string `json:"checked,omitempty"`
Sources []string `json:"sources,omitempty"`
}
Verdict is a marketplace's judgement of a photo.
type WaitOptions ¶
type WaitOptions struct {
// Interval is the time between polls (default DefaultWaitInterval, 2 s).
Interval time.Duration
// Timeout is how long to wait in all (default DefaultWaitTimeout,
// 10 min).
Timeout time.Duration
}
WaitOptions say how Jobs.Wait polls. Zero fields mean the defaults.
type WatermarkOptions ¶
type WatermarkOptions struct {
// Text is the text to draw, up to 200 characters, in a bold sans-serif
// with Latin, Greek and Cyrillic letters.
Text string
// Watermark is an image to put on the photo, such as a logo; a PNG with
// transparency works best. The zero Input means none.
Watermark Input
// Color is the text's colour: "white" (the default), "black", "#rrggbb".
Color string
// Position is "top-left", "top", "top-right", "left", "center", "right",
// "bottom-left", "bottom" or "bottom-right" (the default).
Position string
// Scale is the mark's width as a percentage of the photo's width, 1–100
// (default 25).
Scale float64
// Opacity goes from 1 to 100 (default 50).
Opacity float64
// Margin is the distance from the edges as a percentage of the photo's
// shorter side, 0–50 (default 3). It is a pointer because 0 (against the
// edge) is a value: use Float.
Margin *float64
// Tile repeats the mark across the whole photo. Position is then unused.
Tile bool
// Format is the output format; the default is the photo's own.
Format string
// Quality is the JPEG/WebP/AVIF quality, 1–100.
Quality int
}
WatermarkOptions say what Watermark puts on the photo, Text or a Watermark image (not both), and where. Zero fields are not sent.
type WebhookError ¶
type WebhookError struct {
Reason string
}
WebhookError is why VerifyWebhook rejected a delivery. Compare with errors.Is against ErrWebhookHeader, ErrWebhookSignature, ErrWebhookTimestamp and ErrWebhookPayload, or catch them all with errors.As and a *WebhookError.
func (*WebhookError) Error ¶
func (e *WebhookError) Error() string
type WebhookSecret ¶
type WebhookSecret struct {
// Secret is the signing key, for VerifyWebhook.
Secret string `json:"secret"`
// Header is the name of the signature header, "Photos-Signature".
Header string `json:"header"`
// Scheme describes how the signature is made.
Scheme string `json:"scheme"`
}
WebhookSecret is the key job webhooks are signed with.