Context
The image address displays in portrait orientation on other systems, and the browser also shows it correctly. However, when loaded on the HarmonyOS system, it appears in landscape orientation. The problematic code and screenshot are as follows:
Image("URL of the Image")
.objectFit(ImageFit.Contain)
.width('100%')
.backgroundColor(0x181818)
Description
- EXIF (Exchangeable Image File Format) is an image file format where the data storage is identical to that of the JPEG format. EXIF can be appended to files such as JPEG, TIFF, RIFF, and RAW, adding content related to digital camera shooting information and index images or version information of image processing software.
- ImageSource.getImageProperty: This interface can be used to obtain the value of a specified property key at a given index in an image. It only supports JPEG, PNG, and HEIF files (support varies across different hardware devices) and requires that the file contains EXIF information. The supportedFormats property can be used to check whether EXIF read and write operations for the HEIF format are supported.
Solution
The root cause of the issue is that the Exif information in the image contains a 90° rotation directive, and the HarmonyOS Image component rotates the image based on this information. If you do not want the image to be rotated, the application needs to handle the adaptation itself. Currently, you can try the following adaptation approach:
- Since the Image component cannot directly access the image data, you first need to obtain the image through a network request, setting the expected data type "expectDataType" to "arraybuffer". Then, use "createImageSource" to convert it into an "image.ImageSource" object.
- To retrieve the Exif information of the image, you can use the "getImageProperty" interface (with "PropertyKey" set to "Orientation") to get the rotation information. Then, determine whether the image needs to be rotated. If rotation is required, you can use the "rotate" property of the Image component to perform the rotation.
- Finally, convert the "imageSource" into a "PixelMap" object using the "imageSource.createPixelMap" interface, and then pass the "PixelMap" object to the Image component. Here is a code reference for the above steps:
// Necessary imports
import { image } from '@kit.ImageKit';
import { http } from '@kit.NetworkKit';
async getImageOrientation() {
let angle = 0
const testUrl = 'https://example.com/sample.jpeg'; // Example remote image
// Make HTTP request, expect ArrayBuffer
let mis = await http.createHttp().request(testUrl,
{
expectDataType: http.HttpDataType.ARRAY_BUFFER
}
)
const imageSource: image.ImageSource = image.createImageSource(mis.result as ArrayBuffer);
imageSource.getImageProperty(image.PropertyKey.ORIENTATION)
.then((data: string) => {
if (data === 'Right-top') { // Back-ups for other orientation types could be set
angle = 90
}
})
console.log('Image angle is:' + angle.toString()) // log image orientation
}
Note: To make an HTTP request, do not forget to add the necessary permission:
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:reason"
}
]
If you need to display the image after downloading it, you can create a new "PixelMap" and attach it based on the download.
import { http } from '@kit.NetworkKit';
import { image } from '@kit.ImageKit';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct Index {
@State pixelMap: image.PixelMap | undefined = undefined;
@State angle: number = 0;
// get context properly
context = this.getUIContext().getHostContext() as common.UIAbilityContext;
// Example remote image
private testUrl: string = 'https://example.com/sample.jpeg';
aboutToAppear(): void {
this.downloadAndShow();
}
async downloadAndShow() {
try {
// Make HTTP request, expect ArrayBuffer
let httpRequest = http.createHttp();
let res = await httpRequest.request(this.testUrl, {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER,
connectTimeout: 6000, // Set timeout for safer request
readTimeout: 6000, // Set timeout for safer request
});
if (res.result) {
// Create ImageSource from ArrayBuffer
const imageSource: image.ImageSource = image.createImageSource(res.result as ArrayBuffer);
// Read EXIF orientation
let data = await imageSource.getImageProperty(image.PropertyKey.ORIENTATION);
if (data === 'Right-top') { // Back-ups for other orientation types could be set
this.angle = 90;
}
// Create PixelMap for displaying in Image
this.pixelMap = await imageSource.createPixelMap();
}
} catch (err) {
console.error('Download or decode failed: ' + JSON.stringify(err));
}
}
build() {
RelativeContainer() {
if (this.pixelMap) {
Image(this.pixelMap)
.objectFit(ImageFit.Contain)
.rotate({ angle: this.angle })
.width('100%')
.height('100%')
} else {
Text('Loading...')
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
}
}
.height('100%')
.width('100%')
}
}
Key Takeaways
- When loading images, the Image component may be affected by the Exif information of the image, potentially leading to results that differ from expectations. In such cases, it is necessary to first read and analyze the Exif information of the image, and then configure the image loading with the correct properties.
- If you want to download the image request.downloadFile from @ohos.request and then get the image source with fileIo.openSync (which works only on mobile) from @kit.CoreFileKit can be used.

Top comments (0)