@@ -20,7 +20,6 @@ import (
20
20
"strings"
21
21
22
22
"github.com/kennygrant/sanitize"
23
- pngquant "github.com/manhtai/gopngquant"
24
23
)
25
24
26
25
func FromRequestToFile (req * http.Request , path string ) (string , string , error ) {
@@ -103,14 +102,19 @@ func NewProcessingOps() *operations {
103
102
return ops
104
103
}
105
104
106
- func (o * operation ) addParam (key string , val interface {}) {
105
+ func (o * operation ) AddParam (key string , val interface {}) {
107
106
if o .Params == nil {
108
107
o .Params = make (map [string ]interface {})
109
108
}
110
109
o .Params [key ] = val
111
110
}
112
111
113
- func (o * operations ) add (op string ) {
112
+ func (o * operation ) AddFloat (key string , val float64 ) {
113
+ str := strconv .FormatFloat (val , 'f' , 6 , 64 )
114
+ o .AddParam (key , str )
115
+ }
116
+
117
+ func (o * operations ) Add (op string ) {
114
118
if o .Ops == nil {
115
119
o .Ops = make ([]* operation , 0 )
116
120
}
@@ -119,7 +123,11 @@ func (o *operations) add(op string) {
119
123
})
120
124
}
121
125
122
- func (o * operations ) last () * operation {
126
+ func (o * operations ) OpAt (index int ) * operation {
127
+ return o .Ops [index ]
128
+ }
129
+
130
+ func (o * operations ) LastOp () * operation {
123
131
return o .Ops [len (o .Ops )- 1 ]
124
132
}
125
133
@@ -143,7 +151,7 @@ func ProcessedImage(r io.Reader, imageType string, width int, height int, qualit
143
151
144
152
originalImageType := "jpg"
145
153
if convert {
146
- ops .add ("convert" )
154
+ ops .Add ("convert" )
147
155
148
156
// converting
149
157
if imageType == "jpg" {
@@ -152,15 +160,15 @@ func ProcessedImage(r io.Reader, imageType string, width int, height int, qualit
152
160
} else if imageType == "png" {
153
161
originalImageType = "jpg"
154
162
}
155
- ops .last ().addParam ("type" , imageType )
163
+ ops .LastOp ().AddParam ("type" , imageType )
156
164
}
157
165
158
- ops .add ("fit" )
159
- ops .last ().addParam ("width" , width ) //absolute max
160
- ops .last ().addParam ("height" , height ) // dont need its ratio based
161
- ops .last ().addParam ("stripmeta" , true ) // dont need its ratio based
162
- ops .last ().addParam ("quality" , quality )
163
- // ops.last ().addParam ("compression", quality)
166
+ ops .Add ("fit" )
167
+ ops .LastOp ().AddParam ("width" , width ) //absolute max
168
+ ops .LastOp ().AddParam ("height" , height ) // dont need its ratio based
169
+ ops .LastOp ().AddParam ("stripmeta" , true ) // dont need its ratio based
170
+ ops .LastOp ().AddParam ("quality" , quality )
171
+ // ops.LastOp ().AddParam ("compression", quality)
164
172
bOps , err := json .Marshal (ops .Ops )
165
173
if err != nil {
166
174
return nil , err
@@ -273,71 +281,77 @@ func NewImageHelper(endpoint string, fs FileSaver) *imageProcessHelper {
273
281
}
274
282
}
275
283
276
- func (ip * imageProcessHelper ) GetDimensions (bts io.Reader , ext string ) (width int , height int , err error ) {
284
+ func GetFileExt (filename string ) string {
285
+ ext := filepath .Ext (strings .ToLower (filename ))
286
+ return ext
287
+ }
288
+
289
+ func GetImageDimensions (imgData io.Reader , ext string ) (width int , height int , err error ) {
277
290
ext = strings .ToLower (ext )
278
291
var imgConfig image.Config
279
292
if strings .HasSuffix (ext , "jpeg" ) || strings .HasSuffix (ext , "jpg" ) {
280
- imgConfig , err = jpeg .DecodeConfig (bytes . NewBuffer ( bts ) )
293
+ imgConfig , err = jpeg .DecodeConfig (imgData )
281
294
} else {
282
- imgConfig , err = png .DecodeConfig (bytes . NewBuffer ( bts ) )
295
+ imgConfig , err = png .DecodeConfig (imgData )
283
296
}
284
297
if err != nil {
285
298
return - 1 , - 1 , fmt .Errorf ("failed to get the original image dimensions %v" , err )
286
299
}
287
300
return imgConfig .Width , imgConfig .Width , nil
288
301
}
289
302
290
- func (ip * imageProcessHelper ) ProcessImage (filename string , imgData io.Reader , ops * operations ) (byts * bytes.Buffer , fileName string , url string , err error ) {
291
- ext := filepath .Ext (filename )
303
+ func ProcessImage (filename string , imgData io.Reader , ops * operations ) (byts []byte , err error ) {
304
+ return ProcessImageWithEndpoint (os .Getenv ("IMAGE_PROCESSING_ENDPOINT" ), filename , imgData , ops )
305
+ }
292
306
307
+ func ProcessImageWithEndpoint (endpoint string , filename string , imgData io.Reader , ops * operations ) (b []byte , err error ) {
308
+ if strings .HasSuffix (endpoint , "/" ) {
309
+ endpoint += "/"
310
+ }
311
+ ext := filepath .Ext (filename )
293
312
bOps , err := json .Marshal (ops .Ops )
294
313
if err != nil {
295
- return nil , "" , "" , fmt .Errorf ("json.Marshal %v" , err )
314
+ return nil , fmt .Errorf ("json.Marshal %v" , err )
296
315
}
297
- endpoint := ip . endpoint + "pipeline?operations=" + u .QueryEscape (string (bOps ))
298
- var b bytes.Buffer
299
- mpW := multipart .NewWriter (& b )
316
+ endpoint += "pipeline?operations=" + u .QueryEscape (string (bOps ))
317
+ var buf bytes.Buffer
318
+ mpW := multipart .NewWriter (& buf )
300
319
fw , err := mpW .CreateFormFile ("file" , "placeholder." + ext )
301
320
if err != nil {
302
- return nil , "" , "" , fmt .Errorf ("mpW.CreateFormFile %v" , err )
321
+ return nil , fmt .Errorf ("mpW.CreateFormFile %v" , err )
303
322
// ctx.ErrorJSON(http.StatusOK, "couldn't create form file ", err)
304
323
}
305
324
_ , err = io .Copy (fw , imgData )
306
325
if err != nil {
307
326
// ctx.ErrorJSON(http.StatusOK, "failed to copy from reqFile", err)
308
- return nil , "" , "" , fmt .Errorf ("failed to copy to multipart writer %v" , err )
327
+ return nil , fmt .Errorf ("failed to copy to multipart writer %v" , err )
309
328
}
310
329
err = mpW .Close ()
311
330
if err != nil {
312
- return nil , "" , "" , fmt .Errorf ("failed to close multipart writer %v" , err )
331
+ return nil , fmt .Errorf ("failed to close multipart writer %v" , err )
313
332
}
314
333
315
- req , err := http .NewRequest ("POST" , endpoint , & b )
334
+ req , err := http .NewRequest ("POST" , endpoint , & buf )
316
335
if err != nil {
317
- return nil , "" , "" , fmt .Errorf ("failed to copy from req %v" , err )
336
+ return nil , fmt .Errorf ("failed to copy from req %v" , err )
318
337
}
319
338
req .Header .Set ("Content-Type" , mpW .FormDataContentType ())
320
339
321
340
client := & http.Client {}
322
341
res , err := client .Do (req )
323
342
if err != nil {
324
- return nil , "" , "" , fmt .Errorf ("statuscode %v" , err )
343
+ return nil , fmt .Errorf ("statuscode %v" , err )
325
344
}
326
345
if res .StatusCode != 200 {
327
- return nil , "" , "" , fmt .Errorf ("error status code is : %d" , res .StatusCode )
346
+ return nil , fmt .Errorf ("failed with status code: %d" , res .StatusCode )
328
347
}
329
348
defer res .Body .Close ()
330
349
331
- if ext == "png" {
332
- cmpressedPNG := make ([]byte , 0 )
333
- buf := bytes .NewBuffer (cmpressedPNG )
334
- err = pngquant .CompressPng (res .Body , buf , 5 )
335
- if err != nil {
336
- return nil , "" , "" , fmt .Errorf ("pngquant.CompressPng %v" , err )
337
- }
338
- return ip .fileSaver .SaveFile (filename , buf )
350
+ b , err = ioutil .ReadAll (res .Body )
351
+ if err != nil {
352
+ return nil , fmt .Errorf ("failed reading final bytes %v" , err )
339
353
}
340
- return ip . fileSaver . SaveFile ( filename , res . Body )
354
+ return b , nil
341
355
}
342
356
343
357
type LocalFileStorage struct {
@@ -346,27 +360,44 @@ type LocalFileStorage struct {
346
360
}
347
361
348
362
func NewLocalFileStorage (attachmentsFolder string , attachmentsFolderBaseURL string ) * LocalFileStorage {
363
+ if ! strings .HasSuffix (attachmentsFolderBaseURL , "/" ) {
364
+ attachmentsFolderBaseURL += "/"
365
+ }
349
366
return & LocalFileStorage {
350
367
attachmentsFolder ,
351
368
attachmentsFolderBaseURL ,
352
369
}
353
370
}
354
371
355
- func (fs * LocalFileStorage ) SaveFile (filename string , r io.Reader ) (bts * bytes.Buffer , fileName string , url string , err error ) {
356
- filename = getValidFileName (fs .AttachmentsFolder , filename )
372
+ func (fs * LocalFileStorage ) GetURL (filename string ) (url string ) {
373
+ return fs .AttachmentsFolderBaseURL + filename
374
+ }
375
+
376
+ func (fs * LocalFileStorage ) OpenFile (filename string ) (b []byte , fileName string , url string , err error ) {
357
377
f , err := os .OpenFile (fs .AttachmentsFolder + filename , os .O_RDWR | os .O_CREATE , 0666 )
358
378
if err != nil {
359
379
return nil , "" , "" , fmt .Errorf ("Failed to create a file on the filesystem: %v" , err )
360
380
}
361
- defer f . Close ( )
381
+ b , err = ioutil . ReadAll ( f )
362
382
if err != nil {
383
+ return nil , "" , "" , fmt .Errorf ("failed to save the original image: %v" , err )
384
+ }
385
+ return b , filename , fs .GetURL (filename ), nil
386
+ }
363
387
364
- return nil , "" , "" , fmt .Errorf ("failed to get bytes from the original image: %v" , err )
388
+ func (fs * LocalFileStorage ) SaveFile (filename string , r io.Reader ) (fileName string , url string , err error ) {
389
+ filename = getValidFileName (fs .AttachmentsFolder , filename )
390
+ f , err := os .OpenFile (fs .AttachmentsFolder + filename , os .O_RDWR | os .O_CREATE , 0666 )
391
+ if err != nil {
392
+ return "" , "" , fmt .Errorf ("Failed to create a file on the filesystem: %v" , err )
365
393
}
366
- copy := io .TeeReader (r , f )
367
- bts , err = ioutil .ReadAll (copy )
394
+ defer f .Close ()
368
395
if err != nil {
369
- return nil , "" , "" , fmt .Errorf ("failed to save the original image: %v" , err )
396
+ return "" , "" , fmt .Errorf ("failed to get bytes from the original image: %v" , err )
397
+ }
398
+ _ , err = io .Copy (f , r )
399
+ if err != nil {
400
+ return "" , "" , fmt .Errorf ("failed to save the original image: %v" , err )
370
401
}
371
- return bytes . NewBuffer ( bts ), filename , fs .AttachmentsFolderBaseURL + filename , nil
402
+ return filename , fs .AttachmentsFolderBaseURL + filename , nil
372
403
}
0 commit comments