66import java .util .Map ;
77import java .util .SortedMap ;
88import java .util .TreeMap ;
9+ import java .util .regex .Matcher ;
10+ import java .util .regex .Pattern ;
911
1012import com .cloudinary .utils .ObjectUtils ;
1113import com .cloudinary .utils .StringUtils ;
@@ -23,6 +25,8 @@ public class Transformation {
2325
2426 private static final Map DEFAULT_RESPONSIVE_WIDTH_TRANSFORMATION = ObjectUtils .asMap ("width" , "auto" , "crop" , "limit" );
2527 protected static Map responsiveWidthTransformation = null ;
28+ private static final Pattern RANGE_VALUE_RE = Pattern .compile ("^((?:\\ d+\\ .)?\\ d+)([%pP])?$" );
29+ private static final Pattern RANGE_RE = Pattern .compile ("^(\\ d+\\ .)?\\ d+[%pP]?\\ .\\ .(\\ d+\\ .)?\\ d+[%pP]?$" );
2630
2731 public Transformation (Transformation transformation ) {
2832 this (dup (transformation .transformations ));
@@ -172,6 +176,156 @@ public Transformation dpr(int value) {
172176 public Transformation dpr (String value ) {
173177 return param ("dpr" , value );
174178 }
179+
180+ public Transformation duration (String value ) {
181+ return param ("duration" , value );
182+ }
183+
184+ public Transformation duration (float value ) {
185+ return param ("duration" , new Float (value ));
186+ }
187+
188+ public Transformation duration (double value ) {
189+ return param ("duration" , new Double (value ));
190+ }
191+
192+ public Transformation durationPercent (float value ) {
193+ return param ("duration" , new Float (value ).toString () + "p" );
194+ }
195+
196+ public Transformation durationPercent (double value ) {
197+ return param ("duration" , new Double (value ).toString () + "p" );
198+ }
199+
200+ public Transformation startOffset (String value ) {
201+ return param ("start_offset" , value );
202+ }
203+
204+ public Transformation startOffset (float value ) {
205+ return param ("start_offset" , new Float (value ));
206+ }
207+
208+ public Transformation startOffset (double value ) {
209+ return param ("start_offset" , new Double (value ));
210+ }
211+
212+ public Transformation startOffsetPercent (float value ) {
213+ return param ("start_offset" , new Float (value ).toString () + "p" );
214+ }
215+
216+ public Transformation startOffsetPercent (double value ) {
217+ return param ("start_offset" , new Double (value ).toString () + "p" );
218+ }
219+
220+ public Transformation endOffset (String value ) {
221+ return param ("end_offset" , value );
222+ }
223+
224+ public Transformation endOffset (float value ) {
225+ return param ("end_offset" , new Float (value ));
226+ }
227+
228+ public Transformation endOffset (double value ) {
229+ return param ("end_offset" , new Double (value ));
230+ }
231+
232+ public Transformation endOffsetPercent (float value ) {
233+ return param ("end_offset" , new Float (value ).toString () + "p" );
234+ }
235+
236+ public Transformation endOffsetPercent (double value ) {
237+ return param ("end_offset" , new Double (value ).toString () + "p" );
238+ }
239+
240+ public Transformation offset (String value ) {
241+ return param ("offset" , value );
242+ }
243+
244+ public Transformation offset (String [] value ) {
245+ if (value .length < 2 ) throw new IllegalArgumentException ("Offset range must include at least 2 items" );
246+ return param ("offset" , value );
247+ }
248+
249+ public Transformation offset (float [] value ) {
250+ if (value .length < 2 ) throw new IllegalArgumentException ("Offset range must include at least 2 items" );
251+ Number [] numberArray = new Number []{value [0 ], value [1 ]};
252+ return offset (numberArray );
253+ }
254+
255+ public Transformation offset (double [] value ) {
256+ if (value .length < 2 ) throw new IllegalArgumentException ("Offset range must include at least 2 items" );
257+ Number [] numberArray = new Number []{value [0 ], value [1 ]};
258+ return offset (numberArray );
259+ }
260+
261+ public Transformation offset (Number [] value ) {
262+ if (value .length < 2 ) throw new IllegalArgumentException ("Offset range must include at least 2 items" );
263+ return param ("offset" , value );
264+ }
265+
266+ public Transformation videoCodec (String value ) {
267+ return param ("video_codec" , value );
268+ }
269+
270+ public Transformation videoCodec (Map <String , String > value ) {
271+ return param ("video_codec" , value );
272+ }
273+
274+ public Transformation audioCodec (String value ) {
275+ return param ("audio_codec" , value );
276+ }
277+
278+ public Transformation audioFrequency (String value ) {
279+ return param ("audio_frequency" , value );
280+ }
281+
282+ public Transformation audioFrequency (int value ) {
283+ return param ("audio_frequency" , value );
284+ }
285+
286+ public Transformation bitRate (String value ) {
287+ return param ("bit_rate" , value );
288+ }
289+
290+ public Transformation bitRate (int value ) {
291+ return param ("bit_rate" , new Integer (value ));
292+ }
293+
294+ public Transformation videoSampling (String value ) {
295+ return param ("video_sampling" , value );
296+ }
297+
298+ public Transformation videoSamplingFrames (int value ) {
299+ return param ("video_sampling" , value );
300+ }
301+
302+ public Transformation videoSamplingSeconds (Number value ) {
303+ return param ("video_sampling" , value .toString () + "s" );
304+ }
305+
306+ public Transformation videoSamplingSeconds (int value ) {
307+ return videoSamplingSeconds (new Integer (value ));
308+ }
309+
310+ public Transformation videoSamplingSeconds (float value ) {
311+ return videoSamplingSeconds (new Float (value ));
312+ }
313+
314+ public Transformation videoSamplingSeconds (double value ) {
315+ return videoSamplingSeconds (new Double (value ));
316+ }
317+
318+ public Transformation zoom (String value ) {
319+ return param ("zoom" , value );
320+ }
321+
322+ public Transformation zoom (float value ) {
323+ return param ("zoom" , new Float (value ));
324+ }
325+
326+ public Transformation zoom (double value ) {
327+ return param ("zoom" , new Double (value ));
328+ }
175329
176330 public Transformation responsiveWidth (boolean value ) {
177331 return param ("responsive_width" , value );
@@ -279,22 +433,57 @@ public String generate(Map options) {
279433
280434 String flags = StringUtils .join (ObjectUtils .asArray (options .get ("flags" )), "." );
281435
436+ String duration = normRangeValue (options .get ("duration" ));
437+ String startOffset = normRangeValue (options .get ("start_offset" ));
438+ String endOffset = normRangeValue (options .get ("end_offset" ));
439+ String [] offset = splitRange (options .get ("offset" ));
440+ if (offset != null ) {
441+ startOffset = normRangeValue (offset [0 ]);
442+ endOffset = normRangeValue (offset [1 ]);
443+ }
444+
445+ String videoCodec = processVideoCodecParam (options .get ("video_codec" ));
446+ String dpr = ObjectUtils .asString (options .get ("dpr" ), null == defaultDPR ? null : defaultDPR .toString ());
447+
282448 SortedMap <String , String > params = new TreeMap <String , String >();
283- params .put ("w" , width );
284- params .put ("h" , height );
285- params .put ("t" , namedTransformation );
286- params .put ("c" , crop );
449+ params .put ("a" , angle );
287450 params .put ("b" , background );
451+ params .put ("c" , crop );
288452 params .put ("co" , color );
289- params .put ("a" , angle );
290- params .put ("fl" , flags );
291- String dpr = ObjectUtils .asString (options .get ("dpr" ), null == defaultDPR ? null : defaultDPR .toString ());
292453 params .put ("dpr" , dpr );
293-
294- String [] simple_params = new String [] { "x" , "x" , "y" , "y" , "r" , "radius" , "d" , "default_image" , "g" ,
295- "gravity" , "cs" , "color_space" , "p" , "prefix" , "l" , "overlay" , "u" , "underlay" , "f" , "fetch_format" ,
296- "dn" , "density" , "pg" , "page" , "dl" , "delay" , "e" , "effect" , "bo" , "border" , "q" , "quality" , "o" ,
297- "opacity" };
454+ params .put ("du" , duration );
455+ params .put ("eo" , endOffset );
456+ params .put ("fl" , flags );
457+ params .put ("h" , height );
458+ params .put ("so" , startOffset );
459+ params .put ("t" , namedTransformation );
460+ params .put ("vc" , videoCodec );
461+ params .put ("w" , width );
462+
463+ String [] simple_params = new String [] {
464+ "ac" , "audio_codec" ,
465+ "af" , "audio_frequency" ,
466+ "bo" , "border" ,
467+ "br" , "bit_rate" ,
468+ "cs" , "color_space" ,
469+ "d" , "default_image" ,
470+ "dl" , "delay" ,
471+ "dn" , "density" ,
472+ "e" , "effect" ,
473+ "f" , "fetch_format" ,
474+ "g" , "gravity" ,
475+ "l" , "overlay" ,
476+ "o" , "opacity" ,
477+ "p" , "prefix" ,
478+ "pg" , "page" ,
479+ "q" , "quality" ,
480+ "r" , "radius" ,
481+ "u" , "underlay" ,
482+ "vs" , "video_sampling" ,
483+ "x" , "x" ,
484+ "y" , "y" ,
485+ "z" , "zoom" };
486+
298487 for (int i = 0 ; i < simple_params .length ; i += 2 ) {
299488 params .put (simple_params [i ], ObjectUtils .asString (options .get (simple_params [i + 1 ])));
300489 }
@@ -364,5 +553,54 @@ public static void setDefaultIsResponsive(boolean isResponsive) {
364553 public static void setDefaultDPR (Object dpr ) {
365554 defaultDPR = dpr ;
366555 }
556+
557+ private static String [] splitRange (Object range ) {
558+ if (range instanceof String [] && ((String []) range ).length >= 2 ) {
559+ String [] stringArrayRange = ((String []) range );
560+ return new String []{stringArrayRange [0 ], stringArrayRange [1 ]};
561+ } else if (range instanceof Number [] && ((Number []) range ).length >= 2 ) {
562+ Number [] numberArrayRange = ((Number []) range );
563+ return new String []{numberArrayRange [0 ].toString (), numberArrayRange [1 ].toString ()};
564+ } else if (range instanceof String && RANGE_RE .matcher ((String ) range ).matches ()) {
565+ return ((String ) range ).split ("\\ .\\ ." , 2 );
566+ } else {
567+ return null ;
568+ }
569+ }
570+
571+ private static String normRangeValue (Object objectValue ) {
572+ if (objectValue == null ) return null ;
573+ String value = objectValue .toString ();
574+ if (StringUtils .isEmpty (value )) return null ;
575+
576+ Matcher matcher = RANGE_VALUE_RE .matcher (value );
577+
578+ if (!matcher .matches ()) {
579+ return null ;
580+ }
581+
582+ String modifier = "" ;
583+ if (matcher .groupCount () == 2 && !StringUtils .isEmpty (matcher .group (2 ))) {
584+ modifier = "p" ;
585+ }
586+ return matcher .group (1 ) + modifier ;
587+ }
588+
589+ private static String processVideoCodecParam (Object param ) {
590+ StringBuilder outParam = new StringBuilder ();
591+ if (param instanceof String ) {
592+ outParam .append (param );
593+ } if (param instanceof Map <?, ?>) {
594+ Map <String , String > paramMap = ( Map <String , String > ) param ;
595+ outParam .append (paramMap .get ("codec" ));
596+ if (paramMap .containsKey ("profile" )) {
597+ outParam .append (":" ).append (paramMap .get ("profile" ));
598+ if (paramMap .containsKey ("level" )) {
599+ outParam .append (":" ).append (paramMap .get ("level" ));
600+ }
601+ }
602+ }
603+ return outParam .toString ();
604+ }
367605
368606}
0 commit comments