@@ -34,9 +34,28 @@ function Request-ImageEdit {
3434 [ValidateSet (' standard' , ' low' , ' medium' , ' high' , ' auto' )]
3535 [string ][LowerCaseTransformation ()]$Quality = ' auto' ,
3636
37+ [Parameter ()]
38+ [ValidateSet (' transparent' , ' opaque' , ' auto' )]
39+ [string ][LowerCaseTransformation ()]$Background = ' auto' ,
40+
41+ [Parameter ()]
42+ [Alias (' input_fidelity' )]
43+ [ValidateSet (' low' , ' high' )]
44+ [string ][LowerCaseTransformation ()]$InputFidelity = ' low' ,
45+
46+ [Parameter ()]
47+ [Alias (' output_compression' )]
48+ [ValidateRange (0 , 100 )]
49+ [uint16 ]$OutputCompression = 100 ,
50+
51+ [Parameter ()]
52+ [Alias (' output_format' )]
53+ [ValidateSet (' png' , ' jpeg' , ' webp' )]
54+ [string ][LowerCaseTransformation ()]$OutputFormat = ' png' ,
55+
3756 [Parameter (ParameterSetName = ' Format' )]
3857 [Alias (' response_format' )]
39- [ValidateSet (' url' , ' base64' , ' byte' )]
58+ [ValidateSet (' url' , ' base64' , ' byte' , ' object ' )]
4059 [string ]$ResponseFormat = ' url' ,
4160
4261 [Parameter (ParameterSetName = ' Format' )]
@@ -46,6 +65,16 @@ function Request-ImageEdit {
4665 [ValidateNotNullOrEmpty ()]
4766 [string ]$OutFile ,
4867
68+ # region Stream
69+ [Parameter ()]
70+ [switch ]$Stream = $false ,
71+
72+ [Parameter ()]
73+ [Alias (' partial_images' )]
74+ [ValidateRange (0 , 3 )]
75+ [uint16 ]$PartialImages = 0 ,
76+ # endregion Stream
77+
4978 [Parameter ()]
5079 [string ]$User ,
5180
@@ -142,17 +171,37 @@ function Request-ImageEdit {
142171 if ($PSBoundParameters.ContainsKey (' Quality' )) {
143172 $PostBody.quality = $Quality
144173 }
174+ if ($PSBoundParameters.ContainsKey (' InputFidelity' )) {
175+ $PostBody.input_fidelity = $InputFidelity
176+ }
177+ if ($PSBoundParameters.ContainsKey (' Background' )) {
178+ $PostBody.background = $Background
179+ }
180+ if ($PSBoundParameters.ContainsKey (' OutputCompression' )) {
181+ $PostBody.output_compression = $OutputCompression
182+ }
145183 if ($PSBoundParameters.ContainsKey (' User' )) {
146184 $PostBody.user = $User
147185 }
186+ if ($PartialImages -gt 0 ) {
187+ $Stream = $true
188+ $PostBody.partial_images = $PartialImages
189+ }
190+ if ($Stream ) {
191+ $PostBody.stream = [bool ]$Stream
192+ }
148193
149- switch ($ResponseFormat ) {
150- { $Model -like ' gpt-image-*' } {
151- # GPT-Image model does not support response_format parameter
152- break
194+ # GPT-Image model does not support response_format parameter
195+ if ($Model -like ' gpt-image-*' ) {
196+ if ($PSBoundParameters.ContainsKey (' ResponseFormat' ) -and $ResponseFormat -eq ' url' ) {
197+ Write-Warning ' Your specified model does not support response_format=url. Defaulting to object.'
198+ $ResponseFormat = ' object'
153199 }
200+ }
201+
202+ switch ($ResponseFormat ) {
154203 { $PSCmdlet.ParameterSetName -eq ' OutFile' } {
155- $PostBody .response_format = ' b64_json '
204+ $ResponseFormat = ' base64 '
156205 break
157206 }
158207 ' url' {
@@ -168,9 +217,30 @@ function Request-ImageEdit {
168217 break
169218 }
170219 }
220+
221+ if ($Model -like ' gpt-image-*' ) {
222+ # The output_format parameter is only supported for gpt-image-1.
223+ if ($PSBoundParameters.ContainsKey (' OutputFormat' )) {
224+ $PostBody.output_format = $OutputFormat
225+ }
226+ elseif ($PSCmdlet.ParameterSetName -eq ' OutFile' ) {
227+ $ext = [System.IO.Path ]::GetExtension($OutFile ).ToLower()
228+ if ($ext -eq ' .png' ) {
229+ $PostBody.output_format = ' png'
230+ }
231+ elseif ($ext -eq ' .jpeg' -or $ext -eq ' .jpg' ) {
232+ $PostBody.output_format = ' jpeg'
233+ }
234+ elseif ($ext -eq ' .webp' ) {
235+ $PostBody.output_format = ' webp'
236+ }
237+ else {
238+ $PostBody.output_format = ' png'
239+ }
240+ }
241+ }
171242 # endregion
172243
173- # region Send API Request
174244 $splat = @ {
175245 Method = $OpenAIParameter.Method
176246 Uri = $OpenAIParameter.Uri
@@ -184,80 +254,140 @@ function Request-ImageEdit {
184254 AdditionalHeaders = $AdditionalHeaders
185255 AdditionalBody = $AdditionalBody
186256 }
187- $Response = Invoke-OpenAIAPIRequest @splat
188257
189- # error check
190- if ($null -eq $Response ) {
258+ # region Send API Request (Stream)
259+ if ($Stream ) {
260+ # Stream output
261+ Invoke-OpenAIAPIRequestSSE @splat |
262+ Where-Object {
263+ -not [string ]::IsNullOrEmpty($_ )
264+ } | ForEach-Object - Process {
265+ if ($OutputRawResponse ) {
266+ Write-Output $_
267+ }
268+ else {
269+ # Parse response object
270+ try {
271+ $Response = $_ | ConvertFrom-Json - ErrorAction Stop
272+ }
273+ catch {
274+ Write-Error - Exception $_.Exception
275+ }
276+
277+ if ($Response.type -in (' image_edit.partial_image' , ' image_edit.completed' ) -and $Response.b64_json ) {
278+
279+ if ($null -ne $Response.partial_image_index ) {
280+ $pidx = $Response.partial_image_index
281+ Write-Verbose (' Partial image generated. Index:{0}' -f $pidx )
282+ }
283+ else {
284+ $pidx = $null
285+ Write-Verbose ' Final image generated.'
286+ }
287+
288+ # region Output
289+ if ($PSCmdlet.ParameterSetName -eq ' OutFile' ) {
290+ # Save image
291+ $AbsoluteFilePath = $PSCmdlet.GetUnresolvedProviderPathFromPSPath ($OutFile )
292+ $Ext = [System.IO.Path ]::GetExtension($AbsoluteFilePath )
293+ $BaseName = [System.IO.Path ]::GetFileNameWithoutExtension($AbsoluteFilePath )
294+ if ($null -ne $pidx ) {
295+ $FileName = ' {0}-{1}{2}' -f $BaseName , $pidx , $Ext
296+ }
297+ else {
298+ $FileName = ' {0}{1}' -f $BaseName , $Ext
299+ }
300+ $SaveToPath = Join-Path (Split-Path $AbsoluteFilePath - Parent) $FileName
301+
302+ Write-Verbose (' Save image to {0}' -f $SaveToPath )
303+ Write-ByteContent - OutFile $SaveToPath - Bytes ([Convert ]::FromBase64String($Response.b64_json ))
304+ }
305+ elseif ($ResponseFormat -eq ' object' ) {
306+ ParseImageGenerationObject $Response
307+ }
308+ elseif ($ResponseFormat -eq ' base64' ) {
309+ Write-Output ($Response.b64_json )
310+ }
311+ elseif ($ResponseFormat -eq ' byte' ) {
312+ Write-Output (, ([Convert ]::FromBase64String(($Response.b64_json ))))
313+ }
314+ # endregion
315+ }
316+ else {
317+ continue
318+ }
319+ }
320+ }
191321 return
192322 }
193323 # endregion
194324
195- # region Parse response object
196- if ($OutputRawResponse ) {
197- Write-Output $Response
198- return
199- }
200- try {
201- $Response = $Response | ConvertFrom-Json - ErrorAction Stop
202- if ($null -ne $Response.error.message ) {
203- Write-Error - Message (' API returned error: ({0}) {1}' -f $Response.error.code , $Response.error.message )
325+ # region Send API Request
326+ else {
327+ $Response = Invoke-OpenAIAPIRequest @splat
328+
329+ # error check
330+ if ($null -eq $Response ) {
204331 return
205332 }
206- }
207- catch {
208- Write-Error - Exception $_.Exception
209- }
210- if ($null -ne $Response.data ) {
211- $ResponseContent = $Response.data
212- }
213- # endregion
333+ # endregion
214334
215- # region Output
216- if ($PSCmdlet.ParameterSetName -eq ' OutFile' ) {
217- $AbsoluteFilePath = New-ParentFolder - File $OutFile
218-
219- # Save image
220- $ResponseContent | Select-Object - ExpandProperty ' b64_json' | ForEach-Object - Begin { $Suffix = 0 } - Process {
221- if ( $Suffix -gt 0 ) {
222- $Ext = [System.IO.Path ]::GetExtension($AbsoluteFilePath )
223- $BaseName = [System.IO.Path ]::GetFileNameWithoutExtension($AbsoluteFilePath )
224- $FileName = ' {0}-{1}{2}' -f $BaseName , $Suffix , $Ext
225- $SaveToPath = Join-Path (Split-Path $AbsoluteFilePath - Parent) $FileName
226- }
227- else {
228- $SaveToPath = $AbsoluteFilePath
229- }
230-
231- Write-Verbose (' Save image to {0}' -f $SaveToPath )
232- try {
233- [System.IO.File ]::WriteAllBytes($SaveToPath , [Convert ]::FromBase64String($_ ))
234- }
235- catch {
236- Write-Error - Exception $_.Exception
335+ # region Parse response object
336+ if ($OutputRawResponse ) {
337+ Write-Output $Response
338+ return
339+ }
340+ try {
341+ $Response = $Response | ConvertFrom-Json - ErrorAction Stop
342+ if ($null -ne $Response.error.message ) {
343+ Write-Error - Message (' API returned error: ({0}) {1}' -f $Response.error.code , $Response.error.message )
344+ return
237345 }
238- $Suffix ++
239346 }
240- }
241- elseif ($ResponseFormat -eq ' url' ) {
242- Write-Output ($ResponseContent | Select-Object - ExpandProperty ' url' )
243- }
244- elseif ($ResponseFormat -eq ' base64' ) {
245- Write-Output ($ResponseContent | Select-Object - ExpandProperty ' b64_json' )
246- }
247- elseif ($ResponseFormat -eq ' byte' ) {
248- $ByteArrayList = [System.Collections.Generic.List [byte []]]::new()
249- $ResponseContent | Select-Object - ExpandProperty ' b64_json' | ForEach-Object {
250- $ByteArrayList.Add ([Convert ]::FromBase64String($_ ))
347+ catch {
348+ Write-Error - Exception $_.Exception
251349 }
350+ # endregion
252351
253- if ( $ByteArrayList.Count -eq 1 ) {
254- Write-Output ($ByteArrayList [0 ])
352+ # region Output
353+ if ($ResponseFormat -eq ' object' ) {
354+ ParseImageGenerationObject $Response
355+ return
255356 }
256357 else {
257- Write-Output ($ByteArrayList.ToArray ())
358+ $Suffix = 0
359+ foreach ($content in $Response.data ) {
360+ if ($PSCmdlet.ParameterSetName -eq ' OutFile' ) {
361+ $AbsoluteFilePath = $PSCmdlet.GetUnresolvedProviderPathFromPSPath ($OutFile )
362+
363+ # Save image
364+ if ($Suffix -gt 0 ) {
365+ $Ext = [System.IO.Path ]::GetExtension($AbsoluteFilePath )
366+ $BaseName = [System.IO.Path ]::GetFileNameWithoutExtension($AbsoluteFilePath )
367+ $FileName = ' {0}-{1}{2}' -f $BaseName , $Suffix , $Ext
368+ $SaveToPath = Join-Path (Split-Path $AbsoluteFilePath - Parent) $FileName
369+ }
370+ else {
371+ $SaveToPath = $AbsoluteFilePath
372+ }
373+
374+ Write-Verbose (' Save image to {0}' -f $SaveToPath )
375+ Write-ByteContent - OutFile $SaveToPath - Bytes ([Convert ]::FromBase64String($content.b64_json ))
376+ $Suffix ++
377+ }
378+ elseif ($ResponseFormat -eq ' url' ) {
379+ Write-Output ($content | Select-Object - ExpandProperty ' url' )
380+ }
381+ elseif ($ResponseFormat -eq ' base64' ) {
382+ Write-Output ($content | Select-Object - ExpandProperty ' b64_json' )
383+ }
384+ elseif ($ResponseFormat -eq ' byte' ) {
385+ Write-Output (, ([Convert ]::FromBase64String(($content.b64_json ))))
386+ }
387+ }
258388 }
389+ # endregion
259390 }
260- # endregion
261391 }
262392
263393 end {
0 commit comments