commit
40930889f8
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "smart-profile-photo-editor",
|
"name": "smart-profile-photo-editor",
|
||||||
"version": "0.0.1",
|
"version": "1.1.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -2487,11 +2487,6 @@
|
||||||
"isomorphic-fetch": "^2.2.1"
|
"isomorphic-fetch": "^2.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@microsoft/microsoft-graph-types": {
|
|
||||||
"version": "1.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@microsoft/microsoft-graph-types/-/microsoft-graph-types-1.7.0.tgz",
|
|
||||||
"integrity": "sha512-Mxu5H+69F8T5NzV4+U8FkTvpIYYWHsmRZzfAuOlIO0zJJGlVyRIVqpq4NmOdUXGC00vZ73ONgCuzuaksxqDm/Q=="
|
|
||||||
},
|
|
||||||
"@microsoft/node-core-library": {
|
"@microsoft/node-core-library": {
|
||||||
"version": "3.13.0",
|
"version": "3.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@microsoft/node-core-library/-/node-core-library-3.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@microsoft/node-core-library/-/node-core-library-3.13.0.tgz",
|
||||||
|
@ -4264,22 +4259,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@pnp/graph": {
|
|
||||||
"version": "1.3.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/@pnp/graph/-/graph-1.3.8.tgz",
|
|
||||||
"integrity": "sha512-uBBDrpWNILGBfTxtHqFrdv3YkJZm+jgXOLBp3KR8ocBrTt+yQmkCEwztawYqUhSys6SoDkcFE/DqLIjhyHiBDA==",
|
|
||||||
"requires": {
|
|
||||||
"@microsoft/microsoft-graph-types": "1.7.0",
|
|
||||||
"tslib": "1.10.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"tslib": {
|
|
||||||
"version": "1.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
|
|
||||||
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@pnp/logging": {
|
"@pnp/logging": {
|
||||||
"version": "1.3.8",
|
"version": "1.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@pnp/logging/-/logging-1.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@pnp/logging/-/logging-1.3.8.tgz",
|
||||||
|
@ -4310,21 +4289,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@pnp/sp": {
|
|
||||||
"version": "1.3.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/@pnp/sp/-/sp-1.3.8.tgz",
|
|
||||||
"integrity": "sha512-x85cQL/L5fBYJWqWvDL3e2sHdYZIqUeWifFndsGRk6iLFHTq2DsxNNzTnCpP7JCKUwK6jHpu0JzIuK98E8Hl9w==",
|
|
||||||
"requires": {
|
|
||||||
"tslib": "1.10.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"tslib": {
|
|
||||||
"version": "1.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
|
|
||||||
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@pnp/sp-clientsvc": {
|
"@pnp/sp-clientsvc": {
|
||||||
"version": "1.3.11",
|
"version": "1.3.11",
|
||||||
"resolved": "https://registry.npmjs.org/@pnp/sp-clientsvc/-/sp-clientsvc-1.3.11.tgz",
|
"resolved": "https://registry.npmjs.org/@pnp/sp-clientsvc/-/sp-clientsvc-1.3.11.tgz",
|
||||||
|
@ -4487,6 +4451,21 @@
|
||||||
"react-ace": "5.8.0"
|
"react-ace": "5.8.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@pnp/sp": {
|
||||||
|
"version": "1.3.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@pnp/sp/-/sp-1.3.11.tgz",
|
||||||
|
"integrity": "sha512-NjdeGe81aukiSPelSPjgAFRC1+SrNPTXvTdEqTH+Q1ZvgNtk8bdZp6K6xf9emfeM2qZDOu9GpKZpg0W/emq++g==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "1.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
|
||||||
|
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@uifabric/icons": {
|
"@uifabric/icons": {
|
||||||
"version": "5.8.0",
|
"version": "5.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@uifabric/icons/-/icons-5.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@uifabric/icons/-/icons-5.8.0.tgz",
|
||||||
|
|
|
@ -20,11 +20,6 @@
|
||||||
"@microsoft/sp-office-ui-fabric-core": "1.11.0",
|
"@microsoft/sp-office-ui-fabric-core": "1.11.0",
|
||||||
"@microsoft/sp-property-pane": "1.11.0",
|
"@microsoft/sp-property-pane": "1.11.0",
|
||||||
"@microsoft/sp-webpart-base": "1.11.0",
|
"@microsoft/sp-webpart-base": "1.11.0",
|
||||||
"@pnp/common": "^1.3.8",
|
|
||||||
"@pnp/graph": "^1.3.8",
|
|
||||||
"@pnp/logging": "^1.3.8",
|
|
||||||
"@pnp/odata": "^1.3.8",
|
|
||||||
"@pnp/sp": "^1.3.8",
|
|
||||||
"@pnp/spfx-controls-react": "^1.19.0",
|
"@pnp/spfx-controls-react": "^1.19.0",
|
||||||
"@pnp/spfx-property-controls": "^1.20.0-beta.1472053",
|
"@pnp/spfx-property-controls": "^1.20.0-beta.1472053",
|
||||||
"cropperjs": "^1.5.6",
|
"cropperjs": "^1.5.6",
|
||||||
|
|
|
@ -23,9 +23,11 @@ export class AnalysisService implements IAnalysisService {
|
||||||
new ApiKeyCredentials({ inHeader: { 'Ocp-Apim-Subscription-Key': this.key } }), this.endpoint);
|
new ApiKeyCredentials({ inHeader: { 'Ocp-Apim-Subscription-Key': this.key } }), this.endpoint);
|
||||||
|
|
||||||
var analysis: AnalyzeImageInStreamResponse = (await computerVisionClient.analyzeImageInStream(buf, {
|
var analysis: AnalyzeImageInStreamResponse = (await computerVisionClient.analyzeImageInStream(buf, {
|
||||||
|
details: ["Celebrities"],
|
||||||
visualFeatures: ["Categories",
|
visualFeatures: ["Categories",
|
||||||
"Adult",
|
"Adult",
|
||||||
"Tags",
|
"Tags",
|
||||||
|
"Tags",
|
||||||
"Description",
|
"Description",
|
||||||
"Faces",
|
"Faces",
|
||||||
"Color",
|
"Color",
|
||||||
|
|
|
@ -3,41 +3,41 @@ import * as React from 'react';
|
||||||
import { IAnalysisDialogContentProps } from './IAnalysisDialogContentProps';
|
import { IAnalysisDialogContentProps } from './IAnalysisDialogContentProps';
|
||||||
import { IAnalysisDialogContentState } from './IAnalysisDialogContentState';
|
import { IAnalysisDialogContentState } from './IAnalysisDialogContentState';
|
||||||
|
|
||||||
|
import styles from './AnalysisDialogContent.module.scss';
|
||||||
|
import { css } from "@uifabric/utilities/lib/css";
|
||||||
|
|
||||||
|
// Used for localized text
|
||||||
|
import * as strings from 'ProfilePhotoEditorWebPartStrings';
|
||||||
|
import { Text } from '@microsoft/sp-core-library';
|
||||||
|
|
||||||
|
// Used to determine if we should be making real calls to APIs or just mock calls
|
||||||
|
import { Environment, EnvironmentType } from '@microsoft/sp-core-library';
|
||||||
|
|
||||||
|
// Stuff we use for the dialog
|
||||||
|
import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react/lib/Button';
|
||||||
|
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||||
|
import {
|
||||||
|
MessageBar,
|
||||||
|
MessageBarType
|
||||||
|
} from 'office-ui-fabric-react';
|
||||||
|
import { Image, ImageFit } from 'office-ui-fabric-react/lib/Image';
|
||||||
import { Panel } from 'office-ui-fabric-react/lib/Panel';
|
import { Panel } from 'office-ui-fabric-react/lib/Panel';
|
||||||
import { Label } from 'office-ui-fabric-react/lib/Label';
|
import { Label } from 'office-ui-fabric-react/lib/Label';
|
||||||
import { Shimmer } from 'office-ui-fabric-react/lib/Shimmer';
|
import { Shimmer } from 'office-ui-fabric-react/lib/Shimmer';
|
||||||
import { ProgressIndicator } from 'office-ui-fabric-react/lib/ProgressIndicator';
|
import { ProgressIndicator } from 'office-ui-fabric-react/lib/ProgressIndicator';
|
||||||
|
|
||||||
import styles from './AnalysisDialogContent.module.scss';
|
|
||||||
|
|
||||||
// Used for localized text
|
// Stuff we use for analysis results
|
||||||
import * as strings from 'ProfilePhotoEditorWebPartStrings';
|
|
||||||
|
|
||||||
// Used to determine if we should be making real calls to APIs or just mock calls
|
|
||||||
import { Environment, EnvironmentType } from '@microsoft/sp-core-library';
|
|
||||||
|
|
||||||
import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react/lib/Button';
|
|
||||||
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
|
||||||
import { css } from "@uifabric/utilities/lib/css";
|
|
||||||
import {
|
|
||||||
MessageBar,
|
|
||||||
MessageBarType
|
|
||||||
} from 'office-ui-fabric-react';
|
|
||||||
|
|
||||||
import { Image, ImageFit } from 'office-ui-fabric-react/lib/Image';
|
|
||||||
import { IAnalysisService, AnalysisService, MockAnalysisService } from '../../../../services/AnalysisServices';
|
import { IAnalysisService, AnalysisService, MockAnalysisService } from '../../../../services/AnalysisServices';
|
||||||
import { AnalyzeImageInStreamResponse, ImageTag } from '@azure/cognitiveservices-computervision/esm/models';
|
import { AnalyzeImageInStreamResponse, ImageTag } from '@azure/cognitiveservices-computervision/esm/models';
|
||||||
import AnalysisChecklist from '../AnalysisChecklist/AnalysisChecklist';
|
import AnalysisChecklist from '../AnalysisChecklist/AnalysisChecklist';
|
||||||
|
|
||||||
import { sp } from "@pnp/sp";
|
// This is used if you use the graph client to update pictures
|
||||||
import { MSGraphClient, SPHttpClient } from '@microsoft/sp-http';
|
import { MSGraphClient } from '@microsoft/sp-http';
|
||||||
|
|
||||||
export class AnalysisDialogContent extends
|
export class AnalysisDialogContent extends
|
||||||
React.Component<IAnalysisDialogContentProps, IAnalysisDialogContentState> {
|
React.Component<IAnalysisDialogContentProps, IAnalysisDialogContentState> {
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
constructor(props: IAnalysisDialogContentProps) {
|
constructor(props: IAnalysisDialogContentProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -70,11 +70,23 @@ export class AnalysisDialogContent extends
|
||||||
const analysis: AnalyzeImageInStreamResponse = await service.AnalyzeImage(this.props.imageUrl);
|
const analysis: AnalyzeImageInStreamResponse = await service.AnalyzeImage(this.props.imageUrl);
|
||||||
|
|
||||||
// Evaluate analysis against requirements
|
// Evaluate analysis against requirements
|
||||||
|
|
||||||
|
// Is this a portrait?
|
||||||
const isPortrait: boolean = analysis && analysis.categories && analysis.categories.filter(c => c.name === "people_portrait").length > 0;
|
const isPortrait: boolean = analysis && analysis.categories && analysis.categories.filter(c => c.name === "people_portrait").length > 0;
|
||||||
|
|
||||||
|
// If the portrait valid?
|
||||||
const isPortraitValid: boolean = photoRequirements.requirePortrait ? isPortrait : true;
|
const isPortraitValid: boolean = photoRequirements.requirePortrait ? isPortrait : true;
|
||||||
|
|
||||||
|
// is there only one person in the photo?
|
||||||
const onlyOnePersonValid: boolean = analysis.faces.length === 1;
|
const onlyOnePersonValid: boolean = analysis.faces.length === 1;
|
||||||
|
|
||||||
|
// Is this a clipart?
|
||||||
const isClipartValid: boolean = photoRequirements.allowClipart ? true : analysis.imageType.clipArtType === 0;
|
const isClipartValid: boolean = photoRequirements.allowClipart ? true : analysis.imageType.clipArtType === 0;
|
||||||
|
|
||||||
|
// Is this a line drawing?
|
||||||
const isLinedrawingValid: boolean = photoRequirements.allowLinedrawing ? true : analysis.imageType.lineDrawingType === 0;
|
const isLinedrawingValid: boolean = photoRequirements.allowLinedrawing ? true : analysis.imageType.lineDrawingType === 0;
|
||||||
|
|
||||||
|
// Are we looking at naughty pictures?
|
||||||
const isAdultValid: boolean = photoRequirements.allowAdult ? true : !analysis.adult.isAdultContent;
|
const isAdultValid: boolean = photoRequirements.allowAdult ? true : !analysis.adult.isAdultContent;
|
||||||
const isRacyValid: boolean = photoRequirements.allowRacy ? true : !analysis.adult.isRacyContent;
|
const isRacyValid: boolean = photoRequirements.allowRacy ? true : !analysis.adult.isRacyContent;
|
||||||
const isGoryValid: boolean = photoRequirements.allowGory ? true : !analysis.adult.isGoryContent;
|
const isGoryValid: boolean = photoRequirements.allowGory ? true : !analysis.adult.isGoryContent;
|
||||||
|
@ -91,9 +103,16 @@ export class AnalysisDialogContent extends
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Did we find forbidden keywords
|
||||||
const keywordsValid: boolean = invalidKeywords.length < 1;
|
const keywordsValid: boolean = invalidKeywords.length < 1;
|
||||||
|
|
||||||
console.log("Invalid keywords", invalidKeywords);
|
// Look for celebrities
|
||||||
|
let celebName: string = undefined;
|
||||||
|
const categories = analysis && analysis.categories && analysis.categories.filter(c => c.detail !== undefined && c.detail.celebrities !== undefined);
|
||||||
|
if (categories && categories.length > 0) {
|
||||||
|
// Get the first celebrity
|
||||||
|
celebName = categories[0] && categories[0].detail && categories[0].detail.celebrities[0] && categories[0].detail.celebrities[0].name;
|
||||||
|
}
|
||||||
|
|
||||||
// Photo is valid if it meets all requirements
|
// Photo is valid if it meets all requirements
|
||||||
const isValid: boolean = isPortraitValid
|
const isValid: boolean = isPortraitValid
|
||||||
|
@ -105,6 +124,7 @@ export class AnalysisDialogContent extends
|
||||||
&& isGoryValid
|
&& isGoryValid
|
||||||
&& keywordsValid;
|
&& keywordsValid;
|
||||||
|
|
||||||
|
// Set the state so we can refresh the status
|
||||||
this.setState({
|
this.setState({
|
||||||
isAnalyzing: false,
|
isAnalyzing: false,
|
||||||
analysis,
|
analysis,
|
||||||
|
@ -118,7 +138,8 @@ export class AnalysisDialogContent extends
|
||||||
isRacyValid,
|
isRacyValid,
|
||||||
isGoryValid,
|
isGoryValid,
|
||||||
keywordsValid,
|
keywordsValid,
|
||||||
invalidKeywords
|
invalidKeywords,
|
||||||
|
celebrity: celebName
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +159,8 @@ export class AnalysisDialogContent extends
|
||||||
isLinedrawingValid,
|
isLinedrawingValid,
|
||||||
onlyOnePersonValid,
|
onlyOnePersonValid,
|
||||||
invalidKeywords,
|
invalidKeywords,
|
||||||
keywordsValid } = this.state;
|
keywordsValid,
|
||||||
|
celebrity } = this.state;
|
||||||
|
|
||||||
if (analysis !== undefined) {
|
if (analysis !== undefined) {
|
||||||
console.log("Analysis", analysis);
|
console.log("Analysis", analysis);
|
||||||
|
@ -187,6 +209,11 @@ export class AnalysisDialogContent extends
|
||||||
<div className={styles.iconContainer} ><Icon iconName={isValid ? "CheckMark" : "StatusCircleErrorX"} className={css(styles.icon, isValid ? styles.iconGood : styles.iconBad)} /></div>
|
<div className={styles.iconContainer} ><Icon iconName={isValid ? "CheckMark" : "StatusCircleErrorX"} className={css(styles.icon, isValid ? styles.iconGood : styles.iconBad)} /></div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{!isAnalyzing && celebrity !== undefined &&
|
||||||
|
<div><p>{Text.format(strings.YouLookLikeACelebrity, celebrity)}</p></div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
{!isAnalyzing && isValid &&
|
{!isAnalyzing && isValid &&
|
||||||
<div>{strings.AnalysisGoodLabel}</div>
|
<div>{strings.AnalysisGoodLabel}</div>
|
||||||
}
|
}
|
||||||
|
@ -215,12 +242,12 @@ export class AnalysisDialogContent extends
|
||||||
}
|
}
|
||||||
|
|
||||||
{this.state.isSubmitted &&
|
{this.state.isSubmitted &&
|
||||||
<MessageBar
|
<MessageBar
|
||||||
messageBarType={MessageBarType.success}
|
messageBarType={MessageBarType.success}
|
||||||
isMultiline={false}
|
isMultiline={false}
|
||||||
>
|
>
|
||||||
{strings.SuccessMessage}
|
{strings.SuccessMessage}
|
||||||
</MessageBar>
|
</MessageBar>
|
||||||
}
|
}
|
||||||
|
|
||||||
</Panel>
|
</Panel>
|
||||||
|
@ -240,45 +267,48 @@ export class AnalysisDialogContent extends
|
||||||
}
|
}
|
||||||
|
|
||||||
private onUpdateProfilePhoto = async (_ev?: React.SyntheticEvent<HTMLElement, Event>) => {
|
private onUpdateProfilePhoto = async (_ev?: React.SyntheticEvent<HTMLElement, Event>) => {
|
||||||
console.log("Submitting photo");
|
// Get image array buffer
|
||||||
const profileBlob: Blob = this.props.blob;
|
const profileBlob: Blob = this.props.blob;
|
||||||
|
|
||||||
// Get image array buffer
|
// Submit using the approach you want
|
||||||
this.updateProfilePic(profileBlob);
|
this.updateProfilePicUsingGraph(profileBlob);
|
||||||
|
//this.updateProfilePicUsingPnP(profileBlob);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateProfilePic(buffer) {
|
// private async updateProfilePicUsingPnP(blob: Blob) {
|
||||||
console.log("Update profile pic", buffer);
|
// pnpSetup({
|
||||||
|
// spfxContext: this.props.context
|
||||||
|
// });
|
||||||
|
|
||||||
this.props.context.msGraphClientFactory
|
// console.log("Update profile pic using PnP", blob);
|
||||||
.getClient().then((client: MSGraphClient) => {
|
// const response = await sp.profiles.setMyProfilePic(blob);
|
||||||
client
|
// console.log("Profile property Updated", response);
|
||||||
.api("me/photo/$value")
|
// this.setState({
|
||||||
.version("v1.0").header("Content-Type", buffer.type).put(buffer, (error, res) => {
|
// isSubmitted: true
|
||||||
if (error) {
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Update photo using Graph.
|
||||||
|
// See https://docs.microsoft.com/en-us/graph/api/profilephoto-update?view=graph-rest-1.0&tabs=http
|
||||||
|
private async updateProfilePicUsingGraph(blob: Blob) {
|
||||||
|
this.props.context.msGraphClientFactory
|
||||||
|
.getClient().then((client: MSGraphClient) => {
|
||||||
|
client
|
||||||
|
.api("me/photo/$value")
|
||||||
|
.version("v1.0").header("Content-Type", blob.type).put(blob, (error, _res) => {
|
||||||
|
if (error) {
|
||||||
console.log("Error updating profile", error);
|
console.log("Error updating profile", error);
|
||||||
} else {
|
} else {
|
||||||
console.log("Profile property Updated");
|
console.log("Profile property Updated");
|
||||||
this.setState({
|
this.setState({
|
||||||
isSubmitted: true
|
isSubmitted: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private onDismiss = (_ev?: React.SyntheticEvent<HTMLElement, Event>) => {
|
private onDismiss = (_ev?: React.SyntheticEvent<HTMLElement, Event>) => {
|
||||||
this.props.onDismiss();
|
this.props.onDismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
// private dataURLtoBlob = (dataurl: string): Blob => {
|
|
||||||
// var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
|
|
||||||
// bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
|
|
||||||
// while (n--) {
|
|
||||||
// u8arr[n] = bstr.charCodeAt(n);
|
|
||||||
// }
|
|
||||||
// return new Blob([u8arr], { type: mime });
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,4 +16,5 @@ export interface IAnalysisDialogContentState {
|
||||||
keywordsValid?: boolean;
|
keywordsValid?: boolean;
|
||||||
invalidKeywords?: string[];
|
invalidKeywords?: string[];
|
||||||
isSubmitted: boolean;
|
isSubmitted: boolean;
|
||||||
}
|
celebrity?: string;
|
||||||
|
}
|
||||||
|
|
|
@ -289,8 +289,6 @@ export default class ProfilePhotoEditor extends React.Component<IProfilePhotoEdi
|
||||||
// Get the image to approve
|
// Get the image to approve
|
||||||
const imageToApprove: string = this.cropper.getCroppedCanvas().toDataURL();
|
const imageToApprove: string = this.cropper.getCroppedCanvas().toDataURL();
|
||||||
this.cropper.getCroppedCanvas().toBlob((blob: Blob)=> {
|
this.cropper.getCroppedCanvas().toBlob((blob: Blob)=> {
|
||||||
console.log("Blob", blob);
|
|
||||||
|
|
||||||
const photoRequirements: IPhotoRequirements = {
|
const photoRequirements: IPhotoRequirements = {
|
||||||
allowAdult: this.props.allowAdult,
|
allowAdult: this.props.allowAdult,
|
||||||
allowClipart: this.props.allowClipart,
|
allowClipart: this.props.allowClipart,
|
||||||
|
|
|
@ -10,6 +10,9 @@ import styles from './WebCamDialog.module.scss';
|
||||||
|
|
||||||
import Webcam from "react-webcam";
|
import Webcam from "react-webcam";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the video constraints to be a square from the user-facing camera
|
||||||
|
*/
|
||||||
const videoConstraints = {
|
const videoConstraints = {
|
||||||
width: 300,
|
width: 300,
|
||||||
height: 300,
|
height: 300,
|
||||||
|
@ -41,8 +44,6 @@ export class WebCamDialog extends React.Component<IWebCamDialogProps, IWebCamDia
|
||||||
screenshotFormat="image/jpeg"
|
screenshotFormat="image/jpeg"
|
||||||
videoConstraints={videoConstraints}
|
videoConstraints={videoConstraints}
|
||||||
imageSmoothing={true}
|
imageSmoothing={true}
|
||||||
onUserMedia={() => console.log("OnUserMedia")}
|
|
||||||
onUserMediaError={() => console.log("OnUserMediaError")}
|
|
||||||
screenshotQuality={0.92}
|
screenshotQuality={0.92}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -54,12 +55,19 @@ export class WebCamDialog extends React.Component<IWebCamDialogProps, IWebCamDia
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Captures an image from the web cam
|
||||||
|
*/
|
||||||
private onCapture = () => {
|
private onCapture = () => {
|
||||||
const imageSrc = this.webcamRef.getScreenshot();
|
const imageSrc = this.webcamRef.getScreenshot();
|
||||||
console.log("ImageSrc", imageSrc);
|
|
||||||
this.props.onCapture(imageSrc);
|
this.props.onCapture(imageSrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Dismisses the dialog
|
||||||
|
* @param _ev
|
||||||
|
*/
|
||||||
private onDismiss = (_ev?: React.SyntheticEvent<HTMLElement, Event>) => {
|
private onDismiss = (_ev?: React.SyntheticEvent<HTMLElement, Event>) => {
|
||||||
this.props.onDismiss();
|
this.props.onDismiss();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
define([], function() {
|
define([], function() {
|
||||||
return {
|
return {
|
||||||
|
YouLookLikeACelebrity: "Uh... did anyone ever tell you that you look like {0}? It's uncanny!",
|
||||||
CaptureButtonLabel: "Capture",
|
CaptureButtonLabel: "Capture",
|
||||||
WebCamDialogTitle: "Insert photo from camera",
|
WebCamDialogTitle: "Insert photo from camera",
|
||||||
NoKeywords: "(none)",
|
NoKeywords: "(none)",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
declare interface IProfilePhotoEditorWebPartStrings {
|
declare interface IProfilePhotoEditorWebPartStrings {
|
||||||
|
YouLookLikeACelebrity: string;
|
||||||
CaptureButtonLabel: string;
|
CaptureButtonLabel: string;
|
||||||
WebCamDialogTitle: string;
|
WebCamDialogTitle: string;
|
||||||
NoKeywords: string;
|
NoKeywords: string;
|
||||||
|
|
Loading…
Reference in New Issue