Skip to content

Commit

Permalink
feat: add uprightWidth/uprightHeight props to Ti.Blob
Browse files Browse the repository at this point in the history
Fixes TIMOB-28093
  • Loading branch information
jquick-axway authored and sgtcoolguy committed Sep 2, 2020
1 parent 9254496 commit 09b4591
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 5 deletions.
34 changes: 31 additions & 3 deletions android/titanium/src/java/org/appcelerator/titanium/TiBlob.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ public class TiBlob extends KrollProxy
private Object data;
private String mimetype;
private Bitmap image;
private int width, height;
private int width;
private int height;
private int uprightWidth;
private int uprightHeight;

// This handles the memory cache of images.
private TiBlobLruCache mMemoryCache = TiBlobLruCache.getInstance();
Expand All @@ -81,6 +84,8 @@ private TiBlob(int type, Object data, String mimetype)
this.image = null;
this.width = 0;
this.height = 0;
this.uprightWidth = 0;
this.uprightHeight = 0;
}

/**
Expand Down Expand Up @@ -151,6 +156,8 @@ public static TiBlob blobFromImage(Bitmap image)
blob.image = image;
blob.width = image.getWidth();
blob.height = image.getHeight();
blob.uprightWidth = blob.width;
blob.uprightHeight = blob.height;
return blob;
}

Expand Down Expand Up @@ -280,8 +287,17 @@ public void loadBitmapInfo()

// Update width and height after the file / data is decoded successfully
if (opts.outWidth != -1 && opts.outHeight != -1) {
width = opts.outWidth;
height = opts.outHeight;
this.width = opts.outWidth;
this.height = opts.outHeight;

int rotation = getImageOrientation();
if ((rotation == 90) || (rotation == 270)) {
this.uprightWidth = opts.outHeight;
this.uprightHeight = opts.outWidth;
} else {
this.uprightWidth = opts.outWidth;
this.uprightHeight = opts.outHeight;
}
}
}
}
Expand Down Expand Up @@ -459,6 +475,12 @@ public int getWidth()
return width;
}

@Kroll.getProperty
public int getUprightWidth()
{
return this.uprightWidth;
}

@Kroll.method
@Kroll.getProperty
public int getSize()
Expand All @@ -478,6 +500,12 @@ public int getHeight()
return height;
}

@Kroll.getProperty
public int getUprightHeight()
{
return this.uprightHeight;
}

@Kroll.method
public String toString()
{
Expand Down
42 changes: 40 additions & 2 deletions apidoc/Titanium/Blob.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,29 @@ properties:
description: |
If this blob doesn't represent an image, `height` is reported as 0.
**NOTE**: On SDK versions prior to 9.1.0, Ti.Blob images may have reported in points, not pixels.
**NOTE 1**: On SDK versions prior to 9.1.0, Ti.Blob images may have reported in points, not pixels.
This would occur for images with a higher density/scale returned by <Titanium.UI.View.toImage> or images with `@dx` density suffixes.
You may multiply by <Ti.Platform.displayCaps.logicalDensityFactor> to try and determine the pixels, but this value may be off for some pixel/density combinations.
(i.e. a `10px` image would report as `3` on a `3x` density screen, so multiplying would give you `9` pixels, which is still incorrect)
**NOTE 2**: This represents the height the platform decodes the image to in memory. iOS will automatically
rotate a JPEG based on its EXIF orientation when loaded into memory, but Android does not and instead
rotates it when shown on-screen. You can read the [uprightHeight](Titanium.Blob.uprightHeight) to determine
what the image height will be after rotation, if applicable.
permission: read-only

- name: uprightHeight
type: Number
summary: If the blob references an image, this provides the height in pixels after factoring in EXIF orientation.
description: |
The height of the image in pixels after rotating/flipping it based on its EXIF orientation,
which is commonly the case with JPEGs. Will return the save value as the [height](Titanium.Blob.height)
property if image does not have an EXIF orientation or if the orientation is already upright.
On iOS, properties [height](Titanium.Blob.height) and [uprightHeight](Titanium.Blob.uprightHeight) will always match.
On Android, these properties may differ when loading a JPEG since this platform does not automatically
rotate the loaded image in memory, but it is rotated when displaying it on-screen.
since: "9.2.0"
permission: read-only

- name: width
Expand All @@ -78,10 +97,29 @@ properties:
description: |
If this blob doesn't represent an image, `width` is reported as 0.
**NOTE**: On SDK versions prior to 9.1.0, Ti.Blob images may have reported in points, not pixels.
**NOTE 1**: On SDK versions prior to 9.1.0, Ti.Blob images may have reported in points, not pixels.
This would occur for images with a higher density/scale returned by <Titanium.UI.View.toImage> or images with `@dx` density suffixes.
You may multiply by <Ti.Platform.displayCaps.logicalDensityFactor> to try and determine the pixels, but this value may be off for some pixel/density combinations.
(i.e. a `10px` image would report as `3` on a `3x` density screen, so multiplying would give you `9` pixels, which is still incorrect)
**NOTE 2**: This represents the width the platform decodes the image to in memory. iOS will automatically
rotate a JPEG based on its EXIF orientation when loaded into memory, but Android does not and instead
rotates it when shown on-screen. You can read the [uprightWidth](Titanium.Blob.uprightWidth) to determine
what the image width will be after rotation, if applicable.
permission: read-only

- name: uprightWidth
type: Number
summary: If the blob references an image, this provides the width in pixels after factoring in EXIF orientation.
description: |
The width of the image in pixels after rotating/flipping it based on its EXIF orientation,
which is commonly the case with JPEGs. Will return the save value as the [width](Titanium.Blob.width)
property if image does not have an EXIF orientation or if the orientation is already upright.
On iOS, properties [width](Titanium.Blob.width) and [uprightWidth](Titanium.Blob.uprightWidth) will always match.
On Android, these properties may differ when loading a JPEG since this platform does not automatically
rotate the loaded image in memory, but it is rotated when displaying it on-screen.
since: "9.2.0"
permission: read-only

- name: nativePath
Expand Down
8 changes: 8 additions & 0 deletions iphone/TitaniumKit/TitaniumKit/Sources/API/TiBlob.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ READONLY_PROPERTY(JSValue *, file, File);
Returns height if the blob object is an image, _0_ otherwise.
*/
READONLY_PROPERTY(NSUInteger, height, Height);
/**
Returns height of image after factoring in EXIF orientation, _0_ otherwise.
*/
READONLY_PROPERTY(NSUInteger, uprightHeight, UprightHeight);
/**
Returns the data length.
*/
Expand Down Expand Up @@ -54,6 +58,10 @@ READONLY_PROPERTY(NSString *, text, Text);
Returns width if the blob object is an image, _0_ otherwise.
*/
READONLY_PROPERTY(NSUInteger, width, Width);
/**
Returns width of image after factoring in EXIF orientation, _0_ otherwise.
*/
READONLY_PROPERTY(NSUInteger, uprightWidth, UprightWidth);

// Methods
- (void)append:(TiBlob *)blob;
Expand Down
12 changes: 12 additions & 0 deletions iphone/TitaniumKit/TitaniumKit/Sources/API/TiBlob.m
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ - (NSUInteger)width
}
GETTER_IMPL(NSUInteger, width, Width);

- (NSUInteger)uprightWidth
{
return [self width];
}
GETTER_IMPL(NSUInteger, uprightWidth, UprightWidth);

- (NSUInteger)height
{
[self ensureImageLoaded];
Expand All @@ -83,6 +89,12 @@ - (NSUInteger)height
}
GETTER_IMPL(NSUInteger, height, Height);

- (NSUInteger)uprightHeight
{
return [self height];
}
GETTER_IMPL(NSUInteger, uprightHeight, UprightHeight);

- (NSUInteger)size
{
[self ensureImageLoaded];
Expand Down
Binary file added tests/Resources/ExifFlipHorizontal.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/Resources/ExifFlipVertical.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/Resources/ExifRotate180.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/Resources/ExifRotate270.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/Resources/ExifRotate90.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/Resources/ExifTranspose.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/Resources/ExifTransverse.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions tests/Resources/ti.blob.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ describe('Titanium.Blob', function () {
const blob = Ti.Filesystem.getFile('Logo.png').read();
should(blob.width).be.a.Number();
should(blob.width).be.eql(150);
should(blob.uprightWidth).be.a.Number();
should(blob.uprightWidth).be.eql(blob.width);
// TODO Test that it's read-only
});

Expand All @@ -184,6 +186,8 @@ describe('Titanium.Blob', function () {
const blob = Ti.Filesystem.getFile('Logo.png').read();
should(blob.height).be.a.Number();
should(blob.height).be.eql(150);
should(blob.uprightHeight).be.a.Number();
should(blob.uprightHeight).be.eql(blob.height);
// TODO Test that it's read-only
});

Expand Down Expand Up @@ -391,6 +395,44 @@ describe('Titanium.Blob', function () {
});
});

describe('EXIF orientation', () => {
it('rotate 90', () => {
const blob = Ti.Filesystem.getFile('ExifRotate90.jpg').read();
should(blob.uprightWidth).be.eql(1200);
should(blob.uprightHeight).be.eql(1800);
});
it('rotate 180', () => {
const blob = Ti.Filesystem.getFile('ExifRotate180.jpg').read();
should(blob.uprightWidth).be.eql(1200);
should(blob.uprightHeight).be.eql(1800);
});
it('rotate 270', () => {
const blob = Ti.Filesystem.getFile('ExifRotate270.jpg').read();
should(blob.uprightWidth).be.eql(1200);
should(blob.uprightHeight).be.eql(1800);
});
it('flip horizontal', () => {
const blob = Ti.Filesystem.getFile('ExifFlipHorizontal.jpg').read();
should(blob.uprightWidth).be.eql(1200);
should(blob.uprightHeight).be.eql(1800);
});
it('flip vertical', () => {
const blob = Ti.Filesystem.getFile('ExifFlipVertical.jpg').read();
should(blob.uprightWidth).be.eql(1200);
should(blob.uprightHeight).be.eql(1800);
});
it('transpose', () => {
const blob = Ti.Filesystem.getFile('ExifTranspose.jpg').read();
should(blob.uprightWidth).be.eql(1200);
should(blob.uprightHeight).be.eql(1800);
});
it('transverse', () => {
const blob = Ti.Filesystem.getFile('ExifTransverse.jpg').read();
should(blob.uprightWidth).be.eql(1200);
should(blob.uprightHeight).be.eql(1800);
});
});

// FIXME: This is breaking on Android emulator when setting the image view to the blob
// Canvas: trying to draw too large(211527936bytes) bitmap.
// it breaks on older android devices with an OutOfMemory Error on calling imageAsResized
Expand Down

0 comments on commit 09b4591

Please sign in to comment.