XOne entre sus bondades, ha implementado un módulo de cámara, brindando excelentes potencialidades para esta función y para poder habilitarlas se puede hacer a través de varios alternativas que detallamos a continuación:



En este caso se define un prop type IMG, mediante el cual se accede a la cámara del dispositivo y esta queda embebida en la propia ventana desde la que es invocada .


Ejemplo:

<frame name="frPpal1" width="100%" height="90%" align="top|center" scroll="true" tmargin="5%" >   
    <prop name="FOTO1" title="Foto" width="74%" labelwidth="4" text-border="true" labelbox="false" locked="true" type="T" tmargin="20p" />
    <prop type="B" name="MAP_BTNFOTO1" img="bt_camera.png" width="100p" height="100p" method="ExecuteNode(camera('FOTO1'))" newline="false" tmargin="10p" lmargin="15p" title=" " />
    <prop type="B" name="MAP_BTNDELFOTO1" img="bt_Delete.png" width="100p" height="100p" method="ExecuteNode(delcamera('FOTO1'))" newline="false" tmargin="10p" title=" " />
 
    <prop name="FOTO2" title="Foto 2" width="74%" labelwidth="6" text-border="true" locked="true" type="T" tmargin="20p" />
    <prop type="B" name="MAP_BTNFOTO2" img="camera.png" width="64p" height="64p" method="ExecuteNode(camera('FOTO2'))" newline="false" tmargin="10p" title=" " />
    <prop type="B" name="MAP_BTNDELFOTO2" img="deshacer.png" width="64p" height="64p" method="ExecuteNode(delcamera('FOTO2'))" newline="false" tmargin="10p" title=" " />
 
   <prop name="FOTO3" title="Foto 3" width="74%" labelwidth="6" text-border="true" locked="true" type="T" tmargin="20p" />
   <prop type="B" name="MAP_BTNFOTO3" img="camera.png" width="64p" height="64p" method="ExecuteNode(camera('FOTO3'))" newline="false" tmargin="10p" title=" " />
   <prop type="B" name="MAP_BTNDELFOTO3" img="deshacer.png" width="64p" height="64p" method="ExecuteNode(delcamera('FOTO3'))" newline="false" tmargin="10p" title=" " />
 
  <frame name="frPpal2" width="90%" height="50%" align="top|center" xscroll="true" tmargin="5%" > 
    <prop name="MAP_FOTO1" type="IMG" tmargin="3%" readonly="true" locked="true" width="100%" height="100%" file-maxwidth="800" file-maxheight="600" xlmargin="58%"/>
    <prop name="MAP_FOTO2" type="IMG" tmargin="1%" readonly="true" locked="true" width="30%" height="20%" file-maxwidth="800" file-maxheight="600" newline="false" />
    <prop name="MAP_FOTO3" type="IMG" tmargin="1%" readonly="true" locked="true" width="30%" height="20%" file-maxwidth="800" file-maxheight="600" newline="false" />
  </frame>
</frame>
 
 
<onchange>
	<field name="FOTO1">
		<action name="runscript">
			<script language="javascript">
				self.MAP_FOTO1 = self.FOTO1;
				ui.refresh("MAP_FOTO1");
			</script>
		</action>
	</field>
	<field name="FOTO2">
		<action name="runscript">
			<script language="javascript">
				self.MAP_FOTO2 = self.FOTO2;
				ui.refresh("MAP_FOTO2");
			</script>
		</action>
	</field>
	<field name="FOTO3">
		<action name="runscript">
			<script language="javascript">
				self.MAP_FOTO3 = self.FOTO3;
				ui.refresh("MAP_FOTO3");
			</script>
		</action>
	</field>
</onchange>
 
<camera show-wait-dialog="false">
	<action name="runscript">
	<param name="CAMPO" />
		<script language="javascript">
			ui.startCamera(CAMPO,"photo");
		</script>
	</action>
</camera>
 
<delcamera show-wait-dialog="false">
	<action name="runscript">
	<param name="CAMPO" />
		<script language="javascript">
			self[CAMPO] = "";
		</script>
	</action>
</delcamera>
 
 
  </group>
</coll>


En este caso se define un prop type IMG igual que el ejemplo anterior y lo que cambia es que la llamada a la cámara se hace a través del método ui y un JSON como parámetro.


Ejemplo:

<frame name="frPpal1" width="100%" height="90%" align="top|center" scroll="true" tmargin="5%"> 
     <prop name="MAP_FOTOSELFIE_BT" width="15%" height="8%" tmargin="1%" lmargin="27%" newline="true" onclick="doStartCameraReservaIMG(e,self,'MAP_FOTOSELFIE','MAP_FOTOSELFIE');"   
      img="bt_camera.png" type="B" visible="1" class="propBTInferior colorBTInferior" bgcolor="#00000000" />    
            <frame name="frmselfie" width="90%" height="50%" xlmargin="15%" align="top|center" tmargin="1%" framebox="true" >
                <prop name="MAP_FOTOSELFIE" type="IMG" width="100%" height="100%"  keep-aspect-ratio="false" xclass="nada" />
            </frame>
 
    </frame>
function doStartCameraReservaIMG(evento,obj,propbt,propfoto) {
 
    let sDeviceOS = appData.getGlobalMacro("##DEVICE_OS##");
    let jsParams;
    let ventana;
	if (sDeviceOS == "android") {
        jsParams = {
            width      : 800,
            height     : 600,
            onSuccess  : function(sNuevaFoto) {
                obj[propfoto] = sNuevaFoto;
                ventana = ui.getView(obj);
                if (ventana) {
                    //ventana.refresh(propbt);
                    ventana.refresh();
                }
            },
            onCancelled: function() {
                //Nada
            }
        };
	} else {
	    jsParams = {
            width      : 800,
            height     : 600,
            quality    : 0.6,
            onSuccess  : function(sNuevaFoto) {
                obj[propfoto] = sNuevaFoto;
                ventana = ui.getView(obj);
                if (ventana) {
                    //ventana.refresh(propbt);
                    ventana.refresh();
                }
            },
            onCancelled: function() {
                //Nada
            }
        };
	}
    ui.startCamera(jsParams);
 
}


Cámara con CallBacks

/*
 * Type (opcional), photo/video. Por defecto photo
 * Width (opcional)
 * Height (opcional)
 * UseInternalCamera (opcional), indica si usar la app de fotos del dispositivo
 * o la implementación interna de XOne. Por defecto false
 */
function startPhotoCameraWithCallbacks() {
    let jsParams = {
        type             : "photo",
        width            : 800,
        height           : 600,
        useInternalCamera: false,
        onSuccess        : function(sPhoto) {
            ui.showToast("Todo OK. Foto: " + sPhoto);
        },
        onCancelled      : function() {
            ui.showToast("Se ha cancelado la captura de foto.");
        }
    };
    ui.startCamera(jsParams);
}

Esta es la propia cámara XOne, se define a través de un Prop Type VD. Para este tipo de prop pueden definirse 3 tipos de cámaras al usarse el atributo camera-api=“V1|v2|camerax” .

     <prop name="MAP_CAMERA" type="VD" visible="1" viewmode="camerapreview" width="90%" height="55%" tmargin="0" camera-api="v1" scandit-license="" />
     <prop name="MAP_CAMERA" type="VD" visible="1" viewmode="camerapreview" width="90%" height="55%" tmargin="0" camera-api="v2" scandit-license="" />
     <prop name="MAP_CAMERA" type="VD" visible="1" viewmode="camerapreview" width="90%" height="55%" tmargin="0" camera-api="camerax" scandit-license="" />

Las funciones que brinda este control Cámara se obtienen haciendo:

let control = getControl(“MAP_CAMERA”), donde “MAP_CAMERA” es la propiedad de la cámara.


Estas funciones son:

Funciones Descripción
control.takePicture(params) para hacer foto
control.record para grabar vídeo
control.stopRecording para detener la grabación
control.setFlashMode(sFlashMode) para decirle si el flash está activo, desactivado, automático, etc.
control.setCamera(“front”) para escoger entre la cámara trasera y la frontal.
control.startPreview para iniciar la visualización de la cámara en tiempo real.
control.stopPreview para tener la visualización de la cámara en tiempo real.
control.isCameraOpened para saber si la visualización está activada (devuelve true p false)
control.setAutoFocus para decir si quieres que se active el auto enfoque o no.
control.isAutoFocus true o false, para saber si está activado el auto enfoque.
control.getSupportedAspectRatios devuelve un arreglo con las relaciones de aspecto permitidas por la cámara.
control.getSupportedVideoProfiles devuelve un arreglo con los perfiles de vídeo permitidos por la cámara.
control.getMaxZoom devuelve el max Zoom permisible por la cámara.
control.setZoom(nZoom), pone el zoom según el parámetro. (Son números que van desde 1 hasta el mayor valor permitido por la cámara).
control.setOnCodeScanned, es para escanear (En este caso tiene un parámetro que es una función de callback, para lo que se quiera hacer con el código escaneado).


Ejemplo:


<coll name="CustomCamera" title="" notab="true" editmask="0" sql="SELECT * FROM GEN_USUARIOS">
    <group name="HEADER" id="10" class="groupfixed_header">
        <frame name="frmtitulo" class="frmsuperior">
          <prop name="SALIR" type="B" class="btvolversuper" />
          <prop name="MENU" type="TL" class="tlsuper" title="CAMARA" />
          <prop name="MAP_COLORACTIVO" type="T" visible="0" />
        </frame>
    </group>
 
    <group name="FOOTER" id="0" class="groupfixed_footer">
        <prop name="MAP_GROUP" type="N" visible="0" />
        <prop name="MAP_TOTAL_PAGES" type="N" visible="0" />
        <frame name="FLOAT_FOOTER_FRAME" class="frmsuperior">
          <prop name="MAP_LAST" type="B" img="last.png" title="Anterior" onclick="javascript:prev(self,'ir');" methodx="ExecuteNode(anterior)" forecolor="#FFFFFF" width="45%" height="80%" labelwidth="1" imgsel="last-sel.png" disablevisible="MAP_GROUP=1" />
          <prop name="MAP_LAST_EMPTY" type="B" bgcolor="#00000000" width="45%" height="80%" labelwidth="1" newline="false" disablevisible="MAP_GROUP&gt;1" />
          <prop name="MAP_NEXT" type="B" img="next.png" title="Siguiente " onclick="javascript:next(self,'ir');" methodx="ExecuteNode(siguiente)" forecolor="#FFFFFF" width="45%" height="80%" labelwidth="1" newline="false" lmargin="6%" imgsel="next-sel.png" disablevisible="MAP_GROUP=MAP_TOTAL_PAGES" />
        </frame>
    </group>
 
    <group name="General" id="1">
        <frame name="group1Frame" class="frmtodo" height="1040p" bgcolor="#FFFFFF" align="top|center">
            <frame name="frmTop" tmargin="0" width="100%" height="28%" align="center|top" xbgcolor="#FF040E1A">
                <prop name="MAP_TOGGLE_FLASH_MODE" title="Cambiar Flash"  type="B" visible="1" onclick="javascript:doToggleFlashMode();" class="btnButton" align="center" height="80p" />        
                <prop name="MAP_TOGGLE_CAMERA" title="Cambiar Cámara"  type="B" visible="1" onclick="javascript:doToggleCamera();" lmargin="5%" newline="false" class="btnButton" align="center" height="80p" />        
                <prop name="MAP_TOGGLE_AUTOFOCUS" title="Cambiar Auto Enfoque"  type="B" visible="1" onclick="javascript:doToggleAutoFocus();" class="btnButton" align="center" height="80p" />        
                <prop name="MAP_CAMERA_QUALITY" type="T" visible="1" labelwidth="9" width="700p" height="50p" tmargin="30p" img-height="55p" img-width="60p" linkedto="MAP_CAMERA_QUALITY" linkedfield="DATA" mapcol-values="high,qvga,low,480p,720p,1080p,2160p" title="Calidad de vídeo" showinline="true" text-border="true" />
            </frame>
            <prop name="MAP_CAMERA" type="VD" visible="1" width="80%" height="50%" viewmode="camerapreview" Xcode-type="ean13" />
            <frame name="frmBottom" tmargin="0" width="100%" height="30%" align="center|top" xbgcolor="#FF040E1A">
                <prop name="MAP_TAKE_PICTURE" title="Hacer Foto" type="B" visible="1"  onclick="javascript:takePicture();" class="btnButton" align="center" height="80p"/>
                <prop name="MAP_START_RECORDING" title="Grabar Vídeo" type="B" visible="1" newline="false" lmargin="5%" onclick="javascript:record();" class="btnButton" align="center" disablevisible="MAP_RECORDING=1" height="80p" />
                <prop name="MAP_STOP_RECORDING" title="Detener Vídeo" type="B" visible="1" newline="false" lmargin="5%" onclick="javascript:stopRecording();" class="btnButton" align="center" disablevisible="MAP_RECORDING=0" height="80p" />
                <prop name="MAP_START_PREVIEW" title="Iniciar" type="B" visible="1" onclick="javascript:startPreview();" class="btnButton" align="center" disablevisible="MAP_RECORDING=1" height="80p" />
                <prop name="MAP_STOP_PREVIEW" title="Detener" type="B" visible="1" newline="false" lmargin="5%" onclick="javascript:stopPreview();" class="btnButton" align="center" disablevisible="MAP_RECORDING=1" height="80p" />
            </frame>
 
        </frame>
        <prop name="MAP_RECORDING" type="N" visible="0" />
    </group>
 
function takePicture() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    var params = {
        filename     : "test.jpg",
        saveToGallery: true,
        width        : 360,
        height       : 360,
        onFinished   : function(sFileName) {
            if (!sFileName) {
                ui.showToast("Error de cámara");
            } else {
                ui.showToast("Abriendo nueva foto..."); 
                ui.openFile(sFileName);
            }
        }
    };
    control.takePicture(params);
}
 
function record() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
 
    var currentObj = self;
    let params = {
        quality     : self.MAP_CAMERA_QUALITY,
        maxDuration : 10000,    // Milisegundos
        //maxFileSize : 10485760, // Bytes
        withMicAudio: true,
        onFinished  : function(sFileName) {
            self.MAP_RECORDING=0;
            ui.refresh("MAP_START_RECORDING,MAP_STOP_RECORDING,MAP_START_PREVIEW,MAP_STOP_PREVIEW");
            if (!sFileName) {
                ui.showToast("Error de cámara");
            } else {
                ui.showToast("Nuevo vídeo..."); 
                ui.openFile(sFileName);
            }
        }
    };
    control.record(params);
    self.MAP_RECORDING=1;
    ui.refresh("MAP_START_RECORDING,MAP_STOP_RECORDING,MAP_START_PREVIEW,MAP_STOP_PREVIEW");
}
 
function stopRecording() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    control.stopRecording();
}
 
function startPreview() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    control.startPreview();
}
 
function stopPreview() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    control.stopPreview();
}
 
function isOpened() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    let bOpened = control.isCameraOpened();
    ui.showToast("Abierta: " + bOpened);
}
 
function isAutoFocus() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    let bAutoFocus = control.isAutoFocus();
    ui.showToast("Autofoco: " + bAutoFocus);
}
 
function getSupportedAspectRatios() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    let allAspectRatios = control.getSupportedAspectRatios();
    let sMessage = "Relaciones de aspecto soportadas: ";
    for (let i = 0;i < allAspectRatios.length;i++) {
        sMessage = sMessage + "\n" + allAspectRatios[i];
    }
    ui.msgBox(sMessage, "Mensaje", 0);
}
 
function doSetOnCodeScanned() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    control.setOnCodeScanned(function(evento) {
        let nResult = ui.msgBox("Valor: " + evento.data + "\nTipo: " + evento.type, "¿Código OK?", 4);
        if (nResult == 6) {
            return true;
        } else {
            return false;
        }
    });
}
 
/**
 * Modifica el comportamiento de flash de la cámara.
 * 
 * Valores posibles:
 * 1) on: Siempre encendido al tomar una foto
 * 2) off: Siempre apagado al tomar una foto
 * 3) torch: Siempre encendido
 * 4) auto: Encendido o apagado al tomar una foto dependiendo de lo que diga el
 * sensor de luz
 * 5) red_eye: Encendido o apagado al tomar una foto dependiendo de lo que diga
 * el sensor de luz, en un modo especial que reduce los ojos rojos
 */
function doSetFlashMode(sFlashMode) {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    control.setFlashMode(sFlashMode);
}
 
function doToggleFlashMode() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    let sFlashMode = control.getFlashMode();
    if (sFlashMode == "on") {
        control.setFlashMode("off");
        self.setFieldPropertyValue("MAP_TOGGLE_FLASH_MODE", "img", "flash-off.png");
    } else if (sFlashMode == "off") {
        control.setFlashMode("auto");
        self.setFieldPropertyValue("MAP_TOGGLE_FLASH_MODE", "img", "flash-auto.png");
    } else if (sFlashMode == "auto") {
        control.setFlashMode("torch");
        self.setFieldPropertyValue("MAP_TOGGLE_FLASH_MODE", "img", "flash-torch.png");
    } else if (sFlashMode == "torch") {
        control.setFlashMode("on");
        self.setFieldPropertyValue("MAP_TOGGLE_FLASH_MODE", "img", "flash-on.png");
    }
    ui.refresh("MAP_TOGGLE_FLASH_MODE");
}
 
function doToggleCamera() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    let sCamera = control.getCamera();
    if (sCamera == "front") {
        control.setCamera("back");
    } else if (sCamera == "back") {
        control.setCamera("front");
    }
}
 
function doToggleAutoFocus() {
    let control = getControl("MAP_CAMERA");
    if (!control) {
        return;
    }
    control.setAutoFocus(!control.isAutoFocus());
}
 
function getControl(sPropName) {
    let window = ui.getView(self);
    if (!window) {
        return null;
    }
    let control = window[sPropName];
    if (!control) {
        return null;
    }
    return control;
}


En este caso se habilita un control cámara definiendo a través de un prop type PH, tiene como atributos las imágenes asociadas para lanzar la cámara. Se lanza por defecto la cámara del Sistema Operativo del dispositivo.

Ejemplo:

 <frame name="group2Frame" width="100%" height="100%" xalign="center">
          <prop name="MAP_LABEL4" type="TL" align="center" class="classtl" title="CONTROL HACER FOTO" />
          <prop name="MAP_FOTO" type="PH" width="96%" height="35%" ximg-width="96p" ximg-height="90p"  title="Foto" lmargin="2%" />
          <prop name="MAP_LABEL5" type="TL" class="classtl" title="CONTROL VER FOTO" tmargin="6%"/>
          <prop name="MAP_FOTOVER" type="PH" locked="true" width="96%" height="35%" title="foto" lmargin="2%" />
        </frame>
  </frame>



En este caso es similar al anterior, pero si se define el atributo use-internal-camera=“true” que permite lanzar la cámara interna del framework. Esta opción es recomendable para usar en dispositivos de bajas prestaciones donde el sistema operativo pudiera cerrar aplicaciones en segundo plano.


Ejemplo:

<frame name="group2Frame" width="100%" height="100%" xalign="center">
          <prop name="MAP_LABEL4" type="TL" align="center" class="classtl" title="CONTROL HACER FOTO" />
          <prop name="MAP_FOTO" type="PH" width="96%" height="55%" use-internal-camera="true" img-width="96p" img-height="90p" title="Foto" lmargin="2%" rotate-button="true" img- 
           rotate="bt_rotate.png" />
          <xprop name="MAP_LABEL5" type="TL" class="classtl" title="CONTROL VER FOTO" tmargin="6%" />
          <xprop name="MAP_FOTOVER" type="PH" locked="true" width="96%" height="35%" title="foto" lmargin="2%" />
        </frame>
  </frame>