@akylas/nativescript-app-utils 2.1.3 → 2.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/package.json +3 -3
- package/platforms/android/java/com/nativescript/apputils/ImageUtils.kt +228 -416
- package/typings/android.d.ts +85 -0
- package/typings/ios.d.ts +38 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [2.1.5](https://github.com/akylas/nativescript-app-utils/compare/v2.1.4...v2.1.5) (2024-11-08)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **ios:** getImageSize fix ([fff82d7](https://github.com/akylas/nativescript-app-utils/commit/fff82d79420ecffac199934905bf00683c466913))
|
|
11
|
+
|
|
12
|
+
## [2.1.4](https://github.com/akylas/nativescript-app-utils/compare/v2.1.3...v2.1.4) (2024-10-20)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* package native typings ([06c5e36](https://github.com/akylas/nativescript-app-utils/commit/06c5e36aec45381597981a99203605f6cc0439d3))
|
|
17
|
+
|
|
6
18
|
## [2.1.3](https://github.com/akylas/nativescript-app-utils/compare/v2.1.2...v2.1.3) (2024-10-19)
|
|
7
19
|
|
|
8
20
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akylas/nativescript-app-utils",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.5",
|
|
4
4
|
"description": "Provides API for changing the styles of SystemUI (StatusBar, NavigationBar...) on iOS.",
|
|
5
5
|
"main": "index",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"typings": "index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"tsc": "cpy ../../src/app-utils
|
|
9
|
+
"tsc": "cpy '**/*.d.ts' '../../packages/app-utils' --parents --cwd=../../src/app-utils && tsc -d",
|
|
10
10
|
"build": "npm run tsc",
|
|
11
11
|
"build.watch": "npm run tsc -- -w",
|
|
12
12
|
"build.win": "npm run tsc-win",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"bugs": {
|
|
64
64
|
"url": "https://github.com/akylas/nativescript-app-utils/issues"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "4653c117a97d1999227bc500ec7ed0783a2e3601"
|
|
67
67
|
}
|
|
@@ -1,419 +1,231 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
import java.io.FileNotFoundException
|
|
16
|
-
import java.io.IOException
|
|
17
|
-
import kotlin.math.floor
|
|
18
|
-
import kotlin.math.max
|
|
19
|
-
import kotlin.math.min
|
|
20
|
-
import kotlin.concurrent.thread
|
|
21
|
-
|
|
22
|
-
import com.nativescript.apputils.FunctionCallback
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* This class contains helper functions for processing images
|
|
26
|
-
*
|
|
27
|
-
* @constructor creates image util
|
|
28
|
-
*/
|
|
29
|
-
class ImageUtils {
|
|
30
|
-
|
|
31
|
-
class LoadImageOptions {
|
|
32
|
-
var options: JSONObject? = null
|
|
33
|
-
var sourceWidth = 0
|
|
34
|
-
var sourceHeight = 0
|
|
35
|
-
var width = 0
|
|
36
|
-
var maxWidth = 0
|
|
37
|
-
var height = 0
|
|
38
|
-
var maxHeight = 0
|
|
39
|
-
var keepAspectRatio = true
|
|
40
|
-
var autoScaleFactor = true
|
|
41
|
-
|
|
42
|
-
fun initWithJSON(jsonOpts: JSONObject)
|
|
43
|
-
{
|
|
44
|
-
options = jsonOpts
|
|
45
|
-
if (jsonOpts.has("resizeThreshold")) {
|
|
46
|
-
maxWidth = jsonOpts.optInt("resizeThreshold", maxWidth)
|
|
47
|
-
maxHeight = maxWidth
|
|
48
|
-
} else if (jsonOpts.has("maxSize")) {
|
|
49
|
-
maxWidth = jsonOpts.optInt("maxSize", maxWidth)
|
|
50
|
-
maxHeight = maxWidth
|
|
51
|
-
}
|
|
52
|
-
if (jsonOpts.has("width")) {
|
|
53
|
-
width = jsonOpts.optInt("width", width)
|
|
54
|
-
} else if (jsonOpts.has("maxWidth")) {
|
|
55
|
-
maxWidth = jsonOpts.optInt("maxWidth", maxWidth)
|
|
56
|
-
}
|
|
57
|
-
if (jsonOpts.has("height")) {
|
|
58
|
-
height = jsonOpts.optInt("height", height)
|
|
59
|
-
} else if (jsonOpts.has("maxHeight")) {
|
|
60
|
-
maxHeight = jsonOpts.optInt("maxHeight", maxHeight)
|
|
61
|
-
}
|
|
62
|
-
sourceWidth = jsonOpts.optInt("sourceWidth", sourceWidth)
|
|
63
|
-
sourceHeight = jsonOpts.optInt("sourceHeight", sourceHeight)
|
|
64
|
-
keepAspectRatio = jsonOpts.optBoolean("keepAspectRatio", keepAspectRatio)
|
|
65
|
-
autoScaleFactor = jsonOpts.optBoolean("autoScaleFactor", autoScaleFactor)
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
constructor(options: String?) {
|
|
69
|
-
if (options != null) {
|
|
70
|
-
try {
|
|
71
|
-
val jsonOpts = JSONObject(options)
|
|
72
|
-
initWithJSON(jsonOpts)
|
|
73
|
-
} catch (ignored: JSONException) {
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
constructor(jsonOpts: JSONObject) {
|
|
78
|
-
initWithJSON(jsonOpts)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
var resizeThreshold = 0
|
|
82
|
-
get() { return min(maxWidth, maxHeight)}
|
|
83
|
-
|
|
84
|
-
|
|
1
|
+
import Foundation
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
extension UIImage.Orientation {
|
|
5
|
+
init(_ cgOrientation: CGImagePropertyOrientation) {
|
|
6
|
+
switch cgOrientation {
|
|
7
|
+
case .up: self = .up
|
|
8
|
+
case .upMirrored: self = .upMirrored
|
|
9
|
+
case .down: self = .down
|
|
10
|
+
case .downMirrored: self = .downMirrored
|
|
11
|
+
case .left: self = .left
|
|
12
|
+
case .leftMirrored: self = .leftMirrored
|
|
13
|
+
case .right: self = .right
|
|
14
|
+
case .rightMirrored: self = .rightMirrored
|
|
85
15
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
@objcMembers
|
|
19
|
+
@objc(ImageUtils)
|
|
20
|
+
class ImageUtils : NSObject {
|
|
21
|
+
|
|
22
|
+
static func toJSON(_ str: String?) -> NSDictionary? {
|
|
23
|
+
guard let data = str?.data(using: .utf8, allowLossyConversion: false) else { return nil }
|
|
24
|
+
return try? (JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSDictionary?)
|
|
25
|
+
}
|
|
26
|
+
class LoadImageOptions {
|
|
27
|
+
var width = 0.0
|
|
28
|
+
var maxWidth = 0.0
|
|
29
|
+
var height = 0.0
|
|
30
|
+
var maxHeight = 0.0
|
|
31
|
+
var keepAspectRatio = true
|
|
32
|
+
var autoScaleFactor = true
|
|
33
|
+
|
|
34
|
+
func initWithJSONOptions(_ jsonOpts:NSDictionary?){
|
|
35
|
+
if let jsonOpts = jsonOpts {
|
|
36
|
+
if ((jsonOpts["resizeThreshold"]) != nil) {
|
|
37
|
+
maxWidth = jsonOpts["resizeThreshold"] as! Double
|
|
38
|
+
maxHeight = maxWidth
|
|
39
|
+
} else if ((jsonOpts["maxSize"]) != nil) {
|
|
40
|
+
maxWidth = jsonOpts["maxSize"] as! Double
|
|
41
|
+
maxHeight = maxWidth
|
|
42
|
+
}
|
|
43
|
+
if ((jsonOpts["width"]) != nil) {
|
|
44
|
+
width = jsonOpts["width"] as! Double
|
|
45
|
+
} else if ((jsonOpts["maxWidth"]) != nil) {
|
|
46
|
+
maxWidth = jsonOpts["maxWidth"] as! Double
|
|
47
|
+
}
|
|
48
|
+
if ((jsonOpts["height"]) != nil) {
|
|
49
|
+
height = jsonOpts["height"] as! Double
|
|
50
|
+
} else if ((jsonOpts["maxHeight"]) != nil) {
|
|
51
|
+
maxHeight = jsonOpts["maxHeight"] as! Double
|
|
52
|
+
}
|
|
53
|
+
if ((jsonOpts["keepAspectRatio"]) != nil) {
|
|
54
|
+
keepAspectRatio = jsonOpts["keepAspectRatio"] as! Bool
|
|
55
|
+
}
|
|
56
|
+
if ((jsonOpts["autoScaleFactor"]) != nil) {
|
|
57
|
+
autoScaleFactor = jsonOpts["autoScaleFactor"] as! Bool
|
|
58
|
+
}
|
|
59
|
+
}
|
|
123
60
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
BitmapFactory.decodeFileDescriptor(pfd!!.fileDescriptor, null, bitmapOptions)
|
|
293
|
-
} else {
|
|
294
|
-
BitmapFactory.decodeFile(src, bitmapOptions)
|
|
295
|
-
}
|
|
296
|
-
val rotationAngle: Int
|
|
297
|
-
if (pfd != null) {
|
|
298
|
-
rotationAngle = calculateAngleFromFileDescriptor(pfd.fileDescriptor)
|
|
299
|
-
closePfd(pfd)
|
|
300
|
-
} else {
|
|
301
|
-
rotationAngle = calculateAngleFromFile(src)
|
|
302
|
-
}
|
|
303
|
-
return intArrayOf(bitmapOptions.outWidth, bitmapOptions.outHeight, rotationAngle)
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
fun readBitmapFromFileSync(context: Context, src: String, options: LoadImageOptions?, sourceSize:Pair<Int, Int>?): Bitmap? {
|
|
307
|
-
// val start = System.currentTimeMillis()
|
|
308
|
-
var sourceSize = sourceSize
|
|
309
|
-
if (sourceSize == null && options?.sourceWidth != 0 && options?.sourceHeight != 0) {
|
|
310
|
-
sourceSize = Pair(options!!.sourceWidth, options!!.sourceHeight)
|
|
311
|
-
}
|
|
312
|
-
var bitmap: Bitmap?
|
|
313
|
-
val bitmapOptions = BitmapFactory.Options()
|
|
314
|
-
var pfd: ParcelFileDescriptor? = null
|
|
315
|
-
if (src.startsWith("content://")) {
|
|
316
|
-
val uri = Uri.parse(src)
|
|
317
|
-
val resolver: ContentResolver = context.getContentResolver()
|
|
318
|
-
pfd = try {
|
|
319
|
-
resolver.openFileDescriptor(uri, "r")
|
|
320
|
-
} catch (e: FileNotFoundException) {
|
|
321
|
-
closePfd(pfd)
|
|
322
|
-
throw e;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
if (sourceSize == null) {
|
|
326
|
-
bitmapOptions.inJustDecodeBounds = true
|
|
327
|
-
|
|
328
|
-
if (pfd != null) {
|
|
329
|
-
BitmapFactory.decodeFileDescriptor(pfd!!.fileDescriptor, null, bitmapOptions)
|
|
330
|
-
} else {
|
|
331
|
-
BitmapFactory.decodeFile(src, bitmapOptions)
|
|
332
|
-
}
|
|
333
|
-
sourceSize = Pair(bitmapOptions.outWidth, bitmapOptions.outHeight)
|
|
334
|
-
}
|
|
335
|
-
val opts = ImageAssetOptions(sourceSize, options)
|
|
336
|
-
|
|
337
|
-
val (first, second) = getRequestedImageSize(sourceSize, opts)
|
|
338
|
-
val sampleSize: Int = calculateInSampleSize(
|
|
339
|
-
sourceSize.first, sourceSize.second,
|
|
340
|
-
first,
|
|
341
|
-
second
|
|
342
|
-
)
|
|
343
|
-
val finalBitmapOptions = BitmapFactory.Options()
|
|
344
|
-
finalBitmapOptions.inSampleSize = sampleSize
|
|
345
|
-
if (sampleSize != 1) {
|
|
346
|
-
finalBitmapOptions.inScaled = true;
|
|
347
|
-
finalBitmapOptions.inDensity = sourceSize.first;
|
|
348
|
-
finalBitmapOptions.inTargetDensity = first * sampleSize;
|
|
349
|
-
} else {
|
|
350
|
-
finalBitmapOptions.inScaled = false;
|
|
351
|
-
}
|
|
352
|
-
// read as minimum bitmap as possible (slightly bigger than the requested size)
|
|
353
|
-
bitmap = if (pfd != null) {
|
|
354
|
-
BitmapFactory.decodeFileDescriptor(pfd.fileDescriptor, null, finalBitmapOptions)
|
|
355
|
-
} else {
|
|
356
|
-
BitmapFactory.decodeFile(src, finalBitmapOptions)
|
|
357
|
-
}
|
|
358
|
-
// Log.d("ImageAnalysis", "readBitmapFromFile in ${System.currentTimeMillis() - start} ms")
|
|
359
|
-
if (bitmap != null) {
|
|
360
|
-
val rotationAngle: Int
|
|
361
|
-
if (pfd != null) {
|
|
362
|
-
rotationAngle = calculateAngleFromFileDescriptor(pfd.fileDescriptor)
|
|
363
|
-
closePfd(pfd)
|
|
364
|
-
} else {
|
|
365
|
-
rotationAngle = calculateAngleFromFile(src)
|
|
366
|
-
}
|
|
367
|
-
// if (first !== bitmap.getWidth() || second !== bitmap.getHeight() || rotationAngle != 0) {
|
|
368
|
-
//
|
|
369
|
-
// val matrix = Matrix()
|
|
370
|
-
// if (first !== bitmap.getWidth() || second !== bitmap.getHeight()) {
|
|
371
|
-
// val scale = first.toFloat() / bitmap.width
|
|
372
|
-
// matrix.postScale(scale, scale)
|
|
373
|
-
// }
|
|
374
|
-
// if (rotationAngle != 0) {
|
|
375
|
-
// matrix.postRotate(rotationAngle.toFloat())
|
|
376
|
-
// }
|
|
377
|
-
// bitmap = Bitmap.createBitmap(
|
|
378
|
-
// bitmap,
|
|
379
|
-
// 0,
|
|
380
|
-
// 0,
|
|
381
|
-
// bitmap.getWidth(),
|
|
382
|
-
// bitmap.getHeight(),
|
|
383
|
-
// matrix,
|
|
384
|
-
// false
|
|
385
|
-
// )
|
|
386
|
-
// }
|
|
387
|
-
|
|
388
|
-
if (rotationAngle != 0) {
|
|
389
|
-
val matrix = Matrix()
|
|
390
|
-
matrix.postRotate(rotationAngle.toFloat())
|
|
391
|
-
bitmap = Bitmap.createBitmap(
|
|
392
|
-
bitmap,
|
|
393
|
-
0,
|
|
394
|
-
0,
|
|
395
|
-
bitmap.getWidth(),
|
|
396
|
-
bitmap.getHeight(),
|
|
397
|
-
matrix,
|
|
398
|
-
true
|
|
399
|
-
)
|
|
400
|
-
}
|
|
401
|
-
// Log.d("ImageAnalysis", "readBitmapFromFile2 in ${System.currentTimeMillis() - start} ms")
|
|
402
|
-
}
|
|
403
|
-
return bitmap
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
fun readBitmapFromFileSync(context: Context, src: String, opts: String?): Bitmap? {
|
|
407
|
-
return readBitmapFromFileSync(context, src, LoadImageOptions(opts), null)
|
|
408
|
-
}
|
|
409
|
-
fun readBitmapFromFile(context: Context, src: String, callback: FunctionCallback, opts: String?) {
|
|
410
|
-
thread(start = true) {
|
|
411
|
-
try {
|
|
412
|
-
callback.onResult(null, readBitmapFromFileSync(context, src, opts))
|
|
413
|
-
} catch (e: Exception) {
|
|
414
|
-
callback.onResult(e, null)
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
61
|
+
|
|
62
|
+
init(_ optionsStr:String?) {
|
|
63
|
+
initWithJSONOptions(toJSON(optionsStr))
|
|
64
|
+
}
|
|
65
|
+
init( jsonOpts:NSDictionary?) {
|
|
66
|
+
initWithJSONOptions(jsonOpts)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
class ImageAssetOptions {
|
|
70
|
+
var width = 0.0
|
|
71
|
+
var height = 0.0
|
|
72
|
+
var keepAspectRatio = true
|
|
73
|
+
var autoScaleFactor = true
|
|
74
|
+
init (_ size: CGSize, options: LoadImageOptions?) {
|
|
75
|
+
width = size.width
|
|
76
|
+
height = size.height
|
|
77
|
+
if (options != nil) {
|
|
78
|
+
if (options!.width > 0) {
|
|
79
|
+
width = options!.width
|
|
80
|
+
}
|
|
81
|
+
if (options!.height > 0) {
|
|
82
|
+
height = options!.height
|
|
83
|
+
}
|
|
84
|
+
if (options!.maxWidth > 0) {
|
|
85
|
+
width = min(
|
|
86
|
+
width,
|
|
87
|
+
options!.maxWidth
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
if (options!.maxHeight > 0) {
|
|
91
|
+
height = min(
|
|
92
|
+
height,
|
|
93
|
+
options!.maxHeight
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
keepAspectRatio = options!.keepAspectRatio
|
|
97
|
+
autoScaleFactor = options!.autoScaleFactor
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static func getAspectSafeDimensions(
|
|
103
|
+
_ sourceWidth: Double,
|
|
104
|
+
_ sourceHeight: Double,
|
|
105
|
+
_ reqWidth: Double,
|
|
106
|
+
_ reqHeight: Double
|
|
107
|
+
) -> CGSize {
|
|
108
|
+
let widthCoef = sourceWidth / reqWidth
|
|
109
|
+
let heightCoef = sourceHeight / reqHeight
|
|
110
|
+
let aspectCoef = max(widthCoef, heightCoef)
|
|
111
|
+
return CGSize(width: floor((sourceWidth / aspectCoef)), height: floor((sourceHeight / aspectCoef)))
|
|
112
|
+
}
|
|
113
|
+
static func getRequestedImageSize(_ size: CGSize, _ options: ImageAssetOptions) -> CGSize {
|
|
114
|
+
var reqWidth = options.width
|
|
115
|
+
if (reqWidth <= 0) {
|
|
116
|
+
reqWidth = size.width
|
|
117
|
+
}
|
|
118
|
+
var reqHeight = options.height
|
|
119
|
+
if (reqHeight <= 0) {
|
|
120
|
+
reqHeight = size.height
|
|
121
|
+
}
|
|
122
|
+
if (options.keepAspectRatio) {
|
|
123
|
+
let size2 = getAspectSafeDimensions(
|
|
124
|
+
size.width,
|
|
125
|
+
size.height,
|
|
126
|
+
reqWidth,
|
|
127
|
+
reqHeight
|
|
128
|
+
)
|
|
129
|
+
reqWidth = size2.width
|
|
130
|
+
reqHeight = size2.height
|
|
131
|
+
}
|
|
132
|
+
return CGSize(width: reqWidth, height: reqHeight)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// this scales an image but also return the image "rotated"
|
|
136
|
+
// based on imageOrientation
|
|
137
|
+
static func scaleImage(_ image: UIImage, _ scaledImageSize: CGSize) -> UIImage? {
|
|
138
|
+
// Create a graphics context
|
|
139
|
+
UIGraphicsBeginImageContextWithOptions(scaledImageSize, false, image.scale)
|
|
140
|
+
// Draw the image in the new size
|
|
141
|
+
image.draw(in: CGRect(
|
|
142
|
+
origin: .zero,
|
|
143
|
+
size: scaledImageSize
|
|
144
|
+
))
|
|
145
|
+
// Get the resized, scaled, and rotated image from the context
|
|
146
|
+
let resizedScaledRotatedImage = UIGraphicsGetImageFromCurrentImageContext()
|
|
147
|
+
|
|
148
|
+
// End the graphics context
|
|
149
|
+
UIGraphicsEndImageContext()
|
|
150
|
+
|
|
151
|
+
return resizedScaledRotatedImage
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
static func getImageSize(_ src: String) -> Dictionary<String, Any>? {
|
|
155
|
+
let url = NSURL.fileURL(withPath: src)
|
|
156
|
+
let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil);
|
|
157
|
+
if (imageSource == nil) {
|
|
158
|
+
// Error loading image
|
|
159
|
+
return nil;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let options = [kCGImageSourceShouldCache:false];
|
|
163
|
+
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, options as CFDictionary) as! [NSString: Any]? ;
|
|
164
|
+
var result: Dictionary<String, Any>?;
|
|
165
|
+
if (imageProperties != nil) {
|
|
166
|
+
let width = imageProperties![kCGImagePropertyPixelWidth] as! Double;
|
|
167
|
+
let height = imageProperties![kCGImagePropertyPixelHeight] as! Double;
|
|
168
|
+
var degrees: Int = 0
|
|
169
|
+
let orientation = imageProperties![kCGImagePropertyOrientation];
|
|
170
|
+
if (orientation != nil) {
|
|
171
|
+
let uiOrientation = UIImage.Orientation.init(CGImagePropertyOrientation(rawValue: UInt32(orientation as! Int))!);
|
|
172
|
+
switch uiOrientation {
|
|
173
|
+
case .down, .downMirrored:
|
|
174
|
+
degrees = 180
|
|
175
|
+
break
|
|
176
|
+
case .right, .rightMirrored:
|
|
177
|
+
degrees = -90
|
|
178
|
+
break
|
|
179
|
+
case .left, .leftMirrored:
|
|
180
|
+
degrees = 90
|
|
181
|
+
break
|
|
182
|
+
default:
|
|
183
|
+
degrees = 0
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
result = ["width": width, "height": height, "rotation":degrees];
|
|
188
|
+
}
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
static func readImageFromFileSync(_ src: String, options: NSDictionary?) -> UIImage? {
|
|
194
|
+
let image = UIImage(contentsOfFile: src)
|
|
195
|
+
if let image {
|
|
196
|
+
let size = image.size
|
|
197
|
+
let imageOrientation = image.imageOrientation
|
|
198
|
+
let loadImageOptions = LoadImageOptions(jsonOpts: options)
|
|
199
|
+
let opts = ImageAssetOptions(size, options: loadImageOptions)
|
|
200
|
+
let requestedSize = getRequestedImageSize(size, opts)
|
|
201
|
+
var result: UIImage? = image
|
|
202
|
+
if (requestedSize.width != size.width || requestedSize.height != size.height || imageOrientation != .up) {
|
|
203
|
+
result = scaleImage(image, requestedSize )
|
|
204
|
+
}
|
|
205
|
+
if (options?["jpegQuality"] != nil) {
|
|
206
|
+
result = UIImage.init(data: result!.jpegData(compressionQuality: CGFloat((options!["jpegQuality"] as! Int)) / 100.0)!)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return result
|
|
210
|
+
}
|
|
211
|
+
return nil
|
|
212
|
+
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
static func readImageFromFileSync(_ src: String, _ stringOptions: String?) -> UIImage? {
|
|
216
|
+
let options = toJSON(stringOptions)
|
|
217
|
+
return readImageFromFileSync(src, options: options)
|
|
218
|
+
}
|
|
219
|
+
static func readImageFromFile(_ src: String, _ delegate: NCompletionDelegate?, _ stringOptions: String?) {
|
|
220
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
221
|
+
let options = toJSON(stringOptions)
|
|
222
|
+
// do {
|
|
223
|
+
delegate?.onComplete(readImageFromFileSync(src, stringOptions) as NSObject?, error: nil)
|
|
224
|
+
|
|
225
|
+
// } catch {
|
|
226
|
+
// delegate?.onComplete(readImageFromFileSync(src, stringOptions) as NSObject?, error: error as NSError?)
|
|
227
|
+
//
|
|
228
|
+
// }
|
|
418
229
|
}
|
|
419
|
-
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/unified-signatures */
|
|
2
|
+
declare namespace com {
|
|
3
|
+
export namespace nativescript {
|
|
4
|
+
export namespace apputils {
|
|
5
|
+
export class FunctionCallback extends java.lang.Object {
|
|
6
|
+
public constructor(implementation: { onResult(param0: java.lang.Exception, param1: any): void });
|
|
7
|
+
public onResult(param0: java.lang.Exception, param1: any): void;
|
|
8
|
+
}
|
|
9
|
+
export namespace WorkersContext {
|
|
10
|
+
export class Companion {
|
|
11
|
+
public static getValue(key): any;
|
|
12
|
+
public static setValue(key: string, value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export namespace Utils {
|
|
16
|
+
export class WindowInsetsCallback extends java.lang.Object {
|
|
17
|
+
public constructor(implementation: { onWindowInsetsChange(result: number[]): void });
|
|
18
|
+
public constructor();
|
|
19
|
+
public onWindowInsetsChange(result: number[]): void;
|
|
20
|
+
}
|
|
21
|
+
export class Companion {
|
|
22
|
+
static prepareActivity(arg0: androidx.appcompat.app.AppCompatActivity, applyDynamicColors?: boolean);
|
|
23
|
+
static prepareWindow(arg0: android.view.Window);
|
|
24
|
+
static applyDayNight(context: android.content.Context, applyDynamicColors: boolean);
|
|
25
|
+
static applyDynamicColors(context: android.content.Context);
|
|
26
|
+
static getDimensionFromInt(context: android.content.Context, intToGet): number;
|
|
27
|
+
static getColorFromInt(context: android.content.Context, intToGet): number;
|
|
28
|
+
static getColorFromName(context: android.content.Context, intToGet): number;
|
|
29
|
+
static restartApp(context: android.content.Context, activity: android.app.Activity);
|
|
30
|
+
static getSystemLocale(): java.util.Locale;
|
|
31
|
+
static getRootWindowInsets(view: android.view.View): number[];
|
|
32
|
+
static listenForWindowInsetsChange(view: android.view.View, callback: WindowInsetsCallback);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class ImageUtils extends java.lang.Object {
|
|
36
|
+
public static class: java.lang.Class<ImageUtils>;
|
|
37
|
+
public constructor();
|
|
38
|
+
}
|
|
39
|
+
export namespace ImageUtils {
|
|
40
|
+
export class Companion extends java.lang.Object {
|
|
41
|
+
public static class: java.lang.Class<Companion>;
|
|
42
|
+
public static getImageSize(param0: globalAndroid.content.Context, param1: string): number[];
|
|
43
|
+
public static readBitmapFromFileSync(param0: globalAndroid.content.Context, param1: string, param2?: LoadImageOptions): globalAndroid.graphics.Bitmap;
|
|
44
|
+
public static readBitmapFromFileSync(param0: globalAndroid.content.Context, param1: string, param2: string): globalAndroid.graphics.Bitmap;
|
|
45
|
+
public static readBitmapFromFile(param0: globalAndroid.content.Context, param1: string, callback: FunctionCallback, param2: string);
|
|
46
|
+
public static calculateInSampleSize(param0: number, param1: number, param2: number, param3: number): number;
|
|
47
|
+
public static getTargetFormat(param0: string): globalAndroid.graphics.Bitmap.CompressFormat;
|
|
48
|
+
}
|
|
49
|
+
export class ImageAssetOptions extends java.lang.Object {
|
|
50
|
+
public static class: java.lang.Class<ImageAssetOptions>;
|
|
51
|
+
public setAutoScaleFactor(param0: boolean): void;
|
|
52
|
+
public setWidth(param0: number): void;
|
|
53
|
+
public getAutoScaleFactor(): boolean;
|
|
54
|
+
public constructor(param0: globalAndroid.graphics.BitmapFactory.Options, param1: LoadImageOptions);
|
|
55
|
+
public constructor(param0: globalAndroid.graphics.BitmapFactory.Options);
|
|
56
|
+
public getWidth(): number;
|
|
57
|
+
public setHeight(param0: number): void;
|
|
58
|
+
public setKeepAspectRatio(param0: boolean): void;
|
|
59
|
+
public getKeepAspectRatio(): boolean;
|
|
60
|
+
public getHeight(): number;
|
|
61
|
+
}
|
|
62
|
+
export class LoadImageOptions extends java.lang.Object {
|
|
63
|
+
public static class: java.lang.Class<LoadImageOptions>;
|
|
64
|
+
public setAutoScaleFactor(param0: boolean): void;
|
|
65
|
+
public setWidth(param0: number): void;
|
|
66
|
+
public setMaxHeight(param0: number): void;
|
|
67
|
+
public setMaxWidth(param0: number): void;
|
|
68
|
+
public getResizeThreshold(): number;
|
|
69
|
+
public constructor(param0: string);
|
|
70
|
+
public constructor(param0: org.json.JSONObject);
|
|
71
|
+
public getHeight(): number;
|
|
72
|
+
public initWithJSON(param0: org.json.JSONObject): void;
|
|
73
|
+
public getAutoScaleFactor(): boolean;
|
|
74
|
+
public getWidth(): number;
|
|
75
|
+
public getMaxWidth(): number;
|
|
76
|
+
public getMaxHeight(): number;
|
|
77
|
+
public setHeight(param0: number): void;
|
|
78
|
+
public setKeepAspectRatio(param0: boolean): void;
|
|
79
|
+
public getKeepAspectRatio(): boolean;
|
|
80
|
+
public setResizeThreshold(param0: number): void;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
package/typings/ios.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/* eslint-disable no-redeclare */
|
|
2
|
+
/* eslint-disable no-var */
|
|
3
|
+
declare class NWorkerContext {
|
|
4
|
+
static setValue(key: string, value: any);
|
|
5
|
+
static getValue(key: string);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
declare interface NSLocale {
|
|
9
|
+
ISO639_2LanguageCode();
|
|
10
|
+
}
|
|
11
|
+
declare class ImageUtils extends NSObject {
|
|
12
|
+
static alloc(): ImageUtils; // inherited from NSObject
|
|
13
|
+
|
|
14
|
+
static getAspectSafeDimensions(sourceWidth: number, sourceHeight: number, reqWidth: number, reqHeight: number): CGSize;
|
|
15
|
+
|
|
16
|
+
static getImageSize(src: string): NSDictionary<string, any>;
|
|
17
|
+
|
|
18
|
+
static new(): ImageUtils; // inherited from NSObject
|
|
19
|
+
|
|
20
|
+
static readImageFromFile(src: string, delegate: NCompletionDelegate, stringOptions: string): void;
|
|
21
|
+
|
|
22
|
+
static readImageFromFileSync(src: string, stringOptions: string): UIImage;
|
|
23
|
+
|
|
24
|
+
static readImageFromFileSyncOptions(src: string, options: NSDictionary<any, any>): UIImage;
|
|
25
|
+
|
|
26
|
+
static scaleImage(image: UIImage, scaledImageSize: CGSize): UIImage;
|
|
27
|
+
|
|
28
|
+
static toJSON(str: string): NSDictionary<any, any>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface NCompletionDelegate {
|
|
32
|
+
onCompleteError(result: NSObject, error: NSError): void;
|
|
33
|
+
|
|
34
|
+
onProgress(progress: number): void;
|
|
35
|
+
}
|
|
36
|
+
declare var NCompletionDelegate: {
|
|
37
|
+
prototype: CompletionDelegate;
|
|
38
|
+
};
|