見出し画像

撮影した画像をトリミングしてWebixで利用方法No.027

前回までに紹介した備品管理では、スマホでQRコードの撮影や画像を撮影して格納する動作を紹介していますが、状況によっては、撮影した画像の一部を切り取る操作(トリミング)をしたい場面も多くあると思います。今回、Javascriptでトリミングするライブラリ(croppie)を使い、Webix画面で連携する実装をしましたので紹介します。サンプルソースで実際に動くソースを公開します。実際に操作できます。サンプルソースなので、格納した画像は、その画面の中でしか使用できないので、ご了承ください。
まずは、以下のURLでアクセスしてみてください。PCでもスマホでも動作します。

以下のような画面が表示されます(スマホで紹介します)

一番上のボタン(画像選択(撮影))をクリックすると

以下のような画面になりますでの、事前に撮影した画像を選ぶか、カメラで新規に撮影してください。本記事では、カメラ撮影の例を紹介します。

カメラで撮るを選択し、撮影が完了すると、以下のような画面になります。

対象写真でいい場合は、写真を使用をクリックしてください。再撮影も可能です。画面が切り替わり、トリミング画面になります。

トリミングしたい四角の輪郭を拡大・縮小も可能です。また、画像をスライドして位置を変更もできます。以下は、トリミング領域を大きくして、画像も少し移動しています。この画面でいいときに、保存をクリックしてください。

クリック動作で、サーバに画像を転送して、指定フォルダに画像を保存します。(webixのUPLOAD機能を利用します)
実際にサーバに格納された画像を次の操作で、スマホ画面に読み出して、表示する機能も実装しました。
保存動作後に、画面が切り替わって、アップロードした画像を読み出す画面に切り替わります。

業務アプリでは、直ぐに画像を読みだす操作ではなく、必要時に読み出す機能となりますが、サンプルでは、格納した画像を確認のために、読み出す機能も実装してみました。画像は、本操作以外では、アクセスできませんが、トライアルで操作したときの画像を削除するために、表示した画面で削除をクリックすれば、サーバに保存している画像ファイルも削除します。

削除または、閉じるボタンで、最初の画面に戻ります。
croppieライブラリの詳細は、ネットでも公開されていますので、参考にしてください。今回のポイントは、croppieをそのまま使うのではなく、Webixの画面で連携して使う機能にすることです。
webixのFORUMに記事があったのを参考に実装してみました。

今回のサンプルは、画面が1つ、UPLOAD操作用PHPが1つ、格納した画像を削除するPHPが1つです。
画面webix_sample12.php

<?php
//https://yamasanfarm.sakuraweb.com/webix01/view/ZTEST/webix_sample12.php

    $VER_INFO ="V01L01";
    $TITLE_INFO = "サンプルWebix12";
    $myfilename = basename(__FILE__);   //自分自身のファイル名取得
    define('ROOT_PATH','/home/sunsun/www/webix01'); //ソースを保存しているパス(動作環境に応じて記述する必要あり)
    define('SUB_FOLDER','/webix01');    //サブフォルダを指定したURL
    $userid = '';
    if(isset($_GET['userid'])){
        $userid = $_GET['userid'];
    }
    $logheader = 'userid='.$userid.', '.$myfilename.':';//ログ出力時のヘッダー情報(自ファイル名,ログインIDを付与)
    error_log($logheader.' start '.$myfilename);
?>
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="<?php  echo SUB_FOLDER; ?>/webix_GPL_1020/webix.css" type="text/css"   charset="utf-8">
        <script src="<?php  echo SUB_FOLDER; ?>/webix_GPL_1020/webix.js"></script>
        <link rel="icon" href="<?php  echo SUB_FOLDER; ?>/image/webix_64.ico">
        <script src="<?php  echo SUB_FOLDER; ?>/commonlib/moment-with-locales.js"></script>
    	<script src="<?php  echo SUB_FOLDER; ?>/commonlib/webix_common_lib.js"></script>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.4/croppie.min.css" integrity="sha256-/n6IXDwJAYIh7aLVfRBdduQfdrab96XZR+YjG42V398=" crossorigin="anonymous" />
        <script src="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.4/croppie.min.js" integrity="sha256-bQTfUf1lSu0N421HV2ITHiSjpZ6/5aS6mUNlojIGGWg=" crossorigin="anonymous"></script>
        <title><?php echo $TITLE_INFO.' ('.$VER_INFO.')' ?></title>
	<style>
  .fit_parent {
  	max-width: 100%;
  	max-height: 100%;
  }
  	</style>
    </head>	

<body>
<script type="text/javascript" charset="utf-8">
webix.i18n.setLocale("ja-JP");
webix.ui.fullScreen();


var upload_filename = "";
var equipment_id ="EQ10010";
var path_info = "";
var image_info = "";

function delete_image_data(path_info,image_info){
	var formData = new FormData();
    var access_key = Get_AccessKey();
    formData.append("accesskey",access_key);
    formData.append("userid","admin");
    formData.append("equipment_imagefolder",path_info);
    formData.append("equipment_imagefile",image_info);
    var xhr =webix.ajax().sync().post("<?php  echo SUB_FOLDER; ?>/rest_api/EQ0010/EQ001C_equipment_image_delete.php",formData);
    var resp =  JSON.parse(xhr.responseText);
}

webix.ui({
  view:"window",
  id:"imageWin", 
  position:"center",
  head:{
    view:"toolbar", cols:[
        { view:"label", label: "プレビュー" },
        { view:"button", label: 'キャンセル',
            click:function(){
                $$('imageWin').hide();
            }
        },
        { view:"button", label: '保存',
            click:function(){
                if (body.croppie) {
                    body.croppie.result('blob').then(function(blob) {
                    	var formData = new FormData();
                        var access_key = Get_AccessKey();
                        formData.append("accesskey",access_key);
                        formData.append("userid","admin");
                        formData.append('upload', blob, upload_filename);
                        formData.append("equipment_id",equipment_id);
                        formData.append("editmode",3);  //1:閲覧 2:編集 3:新規登録
                        var xhr =webix.ajax().sync().post("<?php  echo SUB_FOLDER; ?>/rest_api/EQ0010/EQ001D_upload_action.php",formData);
                       	var resp =  JSON.parse(xhr.responseText);
  						if(resp.status == "server"){
  							$$("imageWin").hide();
  							//UPLOADした画像を別の画面で開く
                            path_info = resp.folder;
                            image_info = resp.upload_filename;
                            $$("template1").setValues({
                                   "path":path_info+"/",
                                   "img":image_info,
                                   "width":"120",
                                   "height":"120"
                                 });
                            
  							$$('imageWin2').show();
							webix.message("UPLOAD操作が完了しました。<br>file="+resp.folder+"/<br>"+resp.upload_filename);
						}
  						else{
							webix.alert("のUPLOAD操作に失敗しました。"+resp.error_code);
  						}
                    });
                }
            }
        }
    ]
}, 
  close:true,
  body:{ 
    id:"tmp", 
    width:400,
    height:400,
    top:1,
   left:1,
  }
});

webix.ui({
  view:"window",
  id:'imageWin2',
  fullscreen:true,
  body:{"view":"template",
         id:"template1",
         "template":"<img src='#path##img#'/>"
       },
  head:{ view:"toolbar", cols:[
         { view:"label", label: "アップロード画像" },
         { view:"button", label: '削除',
            click:function(){
                delete_image_data(path_info,image_info);
                $$('imageWin2').hide();
            }
         },
         { view:"button", label: '閉じる',
            click:function(){
                $$('imageWin2').hide();
            }
         },
    ]
  },
  top:1,
  left:1,
  width:300,
  height:300
});

webix.ui({
  rows:[
    { view:"uploader", 
      value:"画像選択(撮影)",
      accept:"image/jpeg, image/png",        
      autosend:false, 
      multiple:false,
      fullscreen:true,
      upload:"<?php  echo SUB_FOLDER; ?>/rest_api/EQ0010/EQ001D_upload_action.php",
      id:"uploadAPI",
      on:{        
        onBeforeFileAdd: function(item){
           var type = item.type.toLowerCase();
           if (type != "jpg" && type != "jpeg" && type != "png"){
               webix.message("PNG または JPG フォーマットのみサポートします。");
               return false;
           }
           var file = item.file;
           upload_filename =file.name;
           var reader = new FileReader();  
           reader.onload = function(event) {
                body = $$("imageWin").getBody();
                if (!body.croppie) {
                    body.croppie = new Croppie(body.$view, {
                        url:event.target.result,
                        enableOrientation:true,
                        enableResize:true
                   });
                }
                else{
                   body.croppie.bind({
                       url:event.target.result
                   });
                }
                $$("imageWin").show();
           };           
           reader.readAsDataURL(file)
           return false;
        },
      }
    },
    {}
  ]
});
var body = $$("imageWin").getBody();

</script>
</body>
</html>

今回のソースは、croppieをインストールしないで、外部を参照しています。
(記事の最後で、リンク先の変更を記述していますので、参考にしてください。)
upload用のPHPソースEQ001D_upload_action.php

 <?php
//======================================================================
//File Name       : EQ001D_upload_action.php
//Encoding        : UTF-8
//Creation Date   : 2024-04-06
// 
//Copyright © 2024 sunsunfarm. All rights reserved.
// 
//This source code or any portion thereof must not be  
//reproduced or used in any manner whatsoever.
//====================================================================== 
    header("Content-Type: text/javascript; charset=utf-8");
    $myfilename = basename(__FILE__);   //自分自身のファイル名取得
    $logheader = 'log:'.$myfilename.':';//ログ出力時のヘッダー情報(自ファイル名を付与)
    include('../../commonlib/svr_common_lib_v3.php');   //
    if($_SERVER["REQUEST_METHOD"] != "POST"){
      error_log($logheader."REQUEST_METHOD NOT POST");
      header("HTTP/1.0 404 Not Found");
      return;
    }
    $userid = "";
    if(isset($_POST['userid'])){
        $userid = $_POST['userid'];
        $error_flag = 1;
    }

    $editmode = "1";
    if(isset($_POST['editmode'])){
        $editmode = $_POST['editmode']; //1:閲覧 2:編集 3:新規登録
    }
    $equipment_id = "";
    if(isset($_POST['equipment_id'])){
        $equipment_id = $_POST['equipment_id'];
    }
    $ph_status = 0; //0 init 1:temp_folder copy 2:target folder move
    $image_folder = '/webix01/image/equipment';
    $base_folder = '/home/sunsun/www'.$image_folder;
    $destination = $base_folder; //my folder
    error_log($logheader."destination =".$destination.' editmode='.$editmode.' equipment_id='.$equipment_id);

    $upload_filename = "";
    
//同一ファイル名の場合、ファイル名を変更して返す    
function unique_filename($org_path, $num=0){
    if( $num > 0){
        $info = pathinfo($org_path);
        $path = $info['dirname'] . "/" . $info['filename'] . "_" . $num;
        if(isset($info['extension'])) $path .= "." . $info['extension'];
    } else {
        $path = $org_path;
    }
     
    if(file_exists($path)){
        $num++;
        return unique_filename($org_path, $num);
    } else {
        return $path;
    }
}   
    
    
    
//Main
    try {
        $config_obj = get_config_obj();
        

        $folder_name =  $destination;
        error_log($logheader."folder_name =".$folder_name);
        if (!file_exists($folder_name)){
            error_log($logheader." create folder:".$folder_name);
            mkdir($folder_name, 0777);
        }
    }catch (Exception $e) {
        error_log($logheader."folder conv error ");
        $res = array("status" => "error","error_code" => -2,"folder" => $image_folder);
        echo json_encode($res);
        exit();
    }

    //ファイルの格納処理
    if(isset($_FILES['upload'])){
        $file = $_FILES['upload'];
        $filename_tmp = $file["name"];
        if($filename_tmp == "image.jpg"){
            error_log($logheader."filename rename to".$upload_filename);
        }
        $upload_filename = $filename_tmp;
        error_log($logheader."filename =".$upload_filename);
        //移動先にファイルがあるかチェック
        $moved_filepath_name = $folder_name."/".$upload_filename;
        
        $moved_filepath_name = unique_filename($moved_filepath_name);
        $file_infos = pathinfo($moved_filepath_name);
        $path_info = $file_infos['dirname'];
        $upload_filename = $file_infos['basename'];
        
        error_log($logheader."moved_filepath_name=".$moved_filepath_name.' upload_filename ='.$upload_filename);
        if (file_exists($moved_filepath_name )){
            //ファイルがあったら、削除して上書き
            error_log($logheader."same file exist: ".$moved_filepath_name);
            
            $result = unlink($moved_filepath_name);
            error_log($logheader."delete temp file:".$moved_filepath_name);
        }

        if($upload_filename != ""){
            $filename = $destination."/".preg_replace("|[\\\/]|", "",$upload_filename);
        }
        else{
            $filename = $destination."/".preg_replace("|[\\\/]|", "",$filename_tmp);
        }
        error_log($logheader."filename =".$filename);
        if ($filename !== "" && file_exists($filename)){
            //先にtempfileを削除する
            $result = unlink($filename);
            error_log($logheader."delete temp file:".$filename);
        }

        if ($filename !== "" && !file_exists($filename)){
            error_log($logheader."move_uploaded_file:".$file["tmp_name"] );
            error_log($logheader."move_size:".$file["size"] );

            move_uploaded_file($file["tmp_name"], $filename);
            
            $ph_status = 1; //0 init 1:temp_folder copy 2:target folder move
            
            //指定フォルダに移動させる
            try {
                $resp = rename($filename, $moved_filepath_name);
                if($resp != true){
                    error_log($logheader."file move error from:".$filename." to:".$moved_filepath_name);
                    $res = array("status" => "error","error_code" => -4,"folder" => $image_folder,"upload_filename" => $upload_filename);
                    echo json_encode($res);
                    exit();
                }
            
            }catch (Exception $e) {
                error_log($logheader."file move error ");
                $res = array("status" => "error","error_code" => -5,"folder" => $image_folder,"upload_filename" => $upload_filename);
                echo json_encode($res);
                exit();
            }
            
            $ph_status = 2; //0 init 1:temp_folder copy 2:target folder move

            error_log($logheader.'$filename='.$filename.' status=server');
            $res = array("status" => "server", "error_code" => 0,"folder" => $image_folder,"upload_filename" => $upload_filename);
            
        }
        else {
            if(file_exists($filename)){
                if($ph_status == 1){
                    //delete temp file
                    $result = unlink($filename);
                    error_log($logheader."delete temp file:".$filename);
                }
                error_log($logheader."filename =".$filename." is exists error_code:-6");
                $res = array("status" => "error","error_code" => -6,"folder" => $image_folder,"upload_filename" => $upload_filename);
            }
            else if($filename == ""){
                if($ph_status == 1){
                    //delete temp file
                    $result = unlink($filename);
                    error_log($logheader."delete temp file:".$filename);
                }
                error_log($logheader."filename is blank error_code:-7");
                $res = array("status" => "error","error_code" => -7,"folder" => $image_folder,"upload_filename" => $upload_filename);
            }
            else{
                if($ph_status == 1){
                    //delete temp file
                    $result = unlink($filename);
                    error_log($logheader."delete temp file:".$filename);
                }
                error_log($logheader."external error  error_code:-8");
                $res = array("status" => "error","error_code" => -8,"folder" => $image_folder,"upload_filename" => $upload_filename);
            }
        }
        echo json_encode($res);
        exit;
    }
    else{
        error_log($logheader." not foud upload file error_code:-1");
        $res = array("status" => "error","error_code" => -39,"folder" => $image_folder,"upload_filename" => $upload_filename);
        echo json_encode($res);
    }

?>

削除用のPHPソースEQ001C_equipment_image_delete.php

 <?php
//======================================================================
//File Name       : EQ001C_equipment_image_delete.php
//Encoding        : UTF-8
//Creation Date   : 2024-04-06
// 
//Copyright © 2024 sunsunfarm. All rights reserved.
// 
//This source code or any portion thereof must not be  
//reproduced or used in any manner whatsoever.
//====================================================================== 
	$myfilename = basename(__FILE__);	//自分自身のファイル名取得
	$logheader = 'log:'.$myfilename.':';//ログ出力時のヘッダー情報(自ファイル名を付与)
	include('../../commonlib/svr_common_lib_v3.php');	//
	if($_SERVER["REQUEST_METHOD"] != "POST"){
	  error_log($logheader."REQUEST_METHOD NOT POST");
	  header("HTTP/1.0 404 Not Found");
	  return;
	}
	$userid = "";
	if(isset($_POST['userid'])){
		$userid = $_POST['userid'];
		$error_flag = 1;
	}

	$equipment_imagefolder = "";
	if(isset($_POST['equipment_imagefolder'])){
		$equipment_imagefolder = $_POST['equipment_imagefolder'];
	}
	$equipment_imagefile = "";
	if(isset($_POST['equipment_imagefile'])){
		$equipment_imagefile = $_POST['equipment_imagefile'];
	}

	$target_folder = '/home/sunsun/www'.$equipment_imagefolder;
	error_log($logheader."delete image file:".$target_folder."/".$equipment_imagefile);

	
//Main
	$res = array("resp" => "ok","error_code" => 0);
	if($equipment_imagefile!= "" && $equipment_imagefolder!= ""){
	   	$result = unlink($target_folder."/".$equipment_imagefile);
	   	if($result){
	    	error_log($logheader."delete file:".$target_folder."/".$equipment_imagefile);
    		$res = array("resp" => "ok","error_code" => 0);
    	}
    	else{
	    	error_log($logheader."delete file:".$target_folder."/".$equipment_imagefile.' error');
    		$res = array("resp" => "ng","error_code" => -1);
    	}
	}
   	echo json_encode($res);
?>

本サンプルを設備管理用に適用して画像撮影の操作性を向上させます。
2024/4/16 一部、環境変更しました。Croppie-2.6.4を提供元からダウンロードして、サーバに保存し、リンク先を変更しました。ZIPファイルをダウンロードして展開すれば、使用できます。

以下の場所に格納しました。
/webix01/commonlib/Croppie-2.6.4/
リンクの変更は、以下のとおりです。

    	<script src="<?php  echo SUB_FOLDER; ?>/commonlib/Croppie-2.6.4/croppie.min.js"></script>
        <link rel="stylesheet" href="<?php  echo SUB_FOLDER; ?>/commonlib/Croppie-2.6.4/croppie.css" type="text/css"   charset="utf-8">


この記事が気に入ったらサポートをしてみませんか?