Skip to content

Commit

Permalink
Reimplement deprecated getViewThumbnail function to resolve regression (
Browse files Browse the repository at this point in the history
#3306) (#3307)

* Reimplement deprecated getViewThumbnail function to resolve regression

(cherry picked from commit 5d8c5ea)

Co-authored-by: Seamus Kirby <[email protected]>
  • Loading branch information
mergify[bot] and skirby1996 authored Mar 8, 2022
1 parent e598b93 commit abc2121
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 9 deletions.
2 changes: 1 addition & 1 deletion common/api/core-frontend.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4954,7 +4954,7 @@ export namespace IModelConnection {
export class Views {
// @internal
constructor(_iModel: IModelConnection);
// @deprecated (undocumented)
// @deprecated
getThumbnail(_viewId: Id64String): Promise<ThumbnailProps>;
getViewList(queryParams: ViewQueryParams): Promise<ViewSpec[]>;
load(viewDefinitionId: Id64String): Promise<ViewState>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/core-backend",
"comment": "",
"type": "none"
}
],
"packageName": "@itwin/core-backend"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/core-frontend",
"comment": "",
"type": "none"
}
],
"packageName": "@itwin/core-frontend"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/rpcinterface-full-stack-tests",
"comment": "",
"type": "none"
}
],
"packageName": "@itwin/rpcinterface-full-stack-tests"
}
16 changes: 13 additions & 3 deletions core/backend/src/rpc-impl/IModelReadRpcImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { GuidString, Id64, Id64String, IModelStatus, Logger } from "@itwin/core-
import {
Code, CodeProps, DbBlobRequest, DbBlobResponse, DbQueryRequest, DbQueryResponse, ElementLoadOptions, ElementLoadProps, ElementProps, EntityMetaData,
EntityQueryParams, FontMapProps, GeoCoordinatesRequestProps, GeoCoordinatesResponseProps, GeometryContainmentRequestProps,
GeometryContainmentResponseProps, GeometrySummaryRequestProps, IModel, IModelConnectionProps, IModelCoordinatesRequestProps,
GeometryContainmentResponseProps, GeometrySummaryRequestProps, ImageSourceFormat, IModel, IModelConnectionProps, IModelCoordinatesRequestProps,
IModelCoordinatesResponseProps, IModelError, IModelReadRpcInterface, IModelRpcOpenProps, IModelRpcProps, MassPropertiesRequestProps,
MassPropertiesResponseProps, ModelProps, NoContentError, RpcInterface, RpcManager, SnapRequestProps, SnapResponseProps, SyncMode,
TextureData, TextureLoadProps, ViewStateLoadProps, ViewStateProps,
Expand Down Expand Up @@ -200,9 +200,19 @@ export class IModelReadRpcImpl extends RpcInterface implements IModelReadRpcInte
return (el === undefined) ? [] : el.getToolTipMessage();
}

/** @deprecated */
/** Send a view thumbnail to the frontend. This is a binary transfer with the metadata in a 16-byte prefix header.
* @deprecated
*/
public async getViewThumbnail(_tokenProps: IModelRpcProps, _viewId: string): Promise<Uint8Array> {
throw new NoContentError();
const iModelDb = await RpcBriefcaseUtility.findOpenIModel(RpcTrace.expectCurrentActivity.accessToken, _tokenProps);
const thumbnail = iModelDb.views.getThumbnail(_viewId);
if (undefined === thumbnail || 0 === thumbnail.image.length)
throw new NoContentError();

const val = new Uint8Array(thumbnail.image.length + 16); // allocate a new buffer 16 bytes larger than the image size
new Uint32Array(val.buffer, 0, 4).set([thumbnail.image.length, thumbnail.format === "jpeg" ? ImageSourceFormat.Jpeg : ImageSourceFormat.Png, thumbnail.width, thumbnail.height]); // Put the metadata in the first 16 bytes.
val.set(thumbnail.image, 16); // put the image data at offset 16 after metadata
return val;
}

public async getDefaultViewId(tokenProps: IModelRpcProps): Promise<Id64String> {
Expand Down
18 changes: 14 additions & 4 deletions core/frontend/src/IModelConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import {
AxisAlignedBox3d, Cartographic, CodeProps, CodeSpec, DbQueryRequest, DbResult, EcefLocation, EcefLocationProps, ECSqlReader, ElementLoadOptions,
ElementProps, EntityQueryParams, FontMap, GeoCoordStatus, GeometryContainmentRequestProps, GeometryContainmentResponseProps,
GeometrySummaryRequestProps, IModel, IModelConnectionProps, IModelError, IModelReadRpcInterface, IModelStatus,
GeometrySummaryRequestProps, ImageSourceFormat, IModel, IModelConnectionProps, IModelError, IModelReadRpcInterface, IModelStatus,
mapToGeoServiceStatus, MassPropertiesRequestProps, MassPropertiesResponseProps, ModelProps, ModelQueryParams, NoContentError, Placement, Placement2d, Placement3d,
QueryBinder, QueryOptions, QueryOptionsBuilder, QueryRowFormat, RpcManager, SnapRequestProps, SnapResponseProps, SnapshotIModelRpcInterface,
TextureData, TextureLoadProps, ThumbnailProps, ViewDefinitionProps, ViewQueryParams, ViewStateLoadProps,
Expand Down Expand Up @@ -1045,11 +1045,21 @@ export namespace IModelConnection { // eslint-disable-line no-redeclare
return viewState;
}

/** @deprecated
* @throws This function is deprecated and will always throw a "no content" error.
/** Get a thumbnail for a view.
* @param viewId The id of the view of the thumbnail.
* @returns A Promise of the ThumbnailProps.
* @throws "No content" error if invalid thumbnail.
* @deprecated
*/
public async getThumbnail(_viewId: Id64String): Promise<ThumbnailProps> {
throw new NoContentError();
// eslint-disable-next-line deprecation/deprecation
const val = await IModelReadRpcInterface.getClientForRouting(this._iModel.routingContext.token).getViewThumbnail(this._iModel.getRpcProps(), _viewId.toString());
const intValues = new Uint32Array(val.buffer, 0, 4);

if (intValues[1] !== ImageSourceFormat.Jpeg && intValues[1] !== ImageSourceFormat.Png)
throw new NoContentError();

return { format: intValues[1] === ImageSourceFormat.Jpeg ? "jpeg" : "png", width: intValues[2], height: intValues[3], image: new Uint8Array(val.buffer, 16, intValues[0]) };
}
}
}
35 changes: 35 additions & 0 deletions full-stack-tests/core/src/frontend/standalone/ModelState.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,39 @@ describe("ModelState", () => {
assert.isTrue(range.low.isAlmostEqual({ x: 288874.1174466432, y: 3803761.1888925503, z: -0.0005 }));
assert.isTrue(range.high.isAlmostEqual({ x: 289160.8417204395, y: 3803959.118535, z: 0.0005 }));
});

it("view thumbnails", async () => {
// eslint-disable-next-line deprecation/deprecation
let thumbnail = await imodel3.views.getThumbnail("0x34");
assert.equal(thumbnail.format, "png", "thumbnail format");
assert.equal(thumbnail.height, 768, "thumbnail height");
assert.equal(thumbnail.width, 768, "thumbnail width");
assert.equal(thumbnail.image.length, 19086, "thumbnail length");
const image = thumbnail.image;
assert.equal(image[0], 0x89);
assert.equal(image[1], 0x50);
assert.equal(image[2], 0x4E);
assert.equal(image[3], 0x47);
assert.equal(image[4], 0x0D);
assert.equal(image[5], 0x0A);
assert.equal(image[6], 0x1A);
assert.equal(image[7], 0x0A);

// eslint-disable-next-line deprecation/deprecation
thumbnail = await imodel2.views.getThumbnail("0x24");
assert.equal(thumbnail.format, "jpeg");
assert.equal(thumbnail.height, 768);
assert.equal(thumbnail.width, 768);
assert.equal(thumbnail.image.length, 18062);
assert.equal(thumbnail.image[3], 224);
assert.equal(thumbnail.image[18061], 217);

try {
// eslint-disable-next-line deprecation/deprecation
await imodel2.views.getThumbnail("0x25");
} catch (_err) {
return;
} // thumbnail doesn't exist
assert.fail("getThumbnail should not return");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Matrix4d, Point3d, XYZProps, YawPitchRollAngles } from "@itwin/core-geo
import {
EcefLocation, GeoCoordStatus, IModelReadRpcInterface, IModelVersion, MassPropertiesOperation, MassPropertiesRequestProps, ModelQueryParams,
} from "@itwin/core-common";
import { CheckpointConnection, IModelApp, IModelConnection, SpatialModelState } from "@itwin/core-frontend";
import { CheckpointConnection, IModelApp, IModelConnection, SpatialModelState, ViewState } from "@itwin/core-frontend";
import { TestFrontendAuthorizationClient } from "@itwin/oidc-signin-tool/lib/cjs/frontend";
import { TestContext } from "./setup/TestContext";

Expand Down Expand Up @@ -172,6 +172,14 @@ describe("IModelReadRpcInterface Methods from an IModelConnection", () => {
expect(result).undefined;
});

it("getViewThumbnail should work as expected", async () => {
const modelQueryParams: ModelQueryParams = { limit: 10, from: ViewState.classFullName };
const modelProps = await iModel.views.queryProps(modelQueryParams);
const viewId = modelProps[0].id!.toString();
const result = await iModel.views.getThumbnail(viewId);
expect(result).to.not.be.undefined;
});

it("getIModelCoordinatesFromGeoCoordinates should work as expected", async () => {
const wgs84Converter = iModel.geoServices.getConverter("WGS84");
const nad27Converter = iModel.geoServices.getConverter("NAD27");
Expand Down

0 comments on commit abc2121

Please sign in to comment.