Symfony2-Crop |如何取回我裁剪的图像?

Posted

技术标签:

【中文标题】Symfony2-Crop |如何取回我裁剪的图像?【英文标题】:Symfony2-Cropit | How to get back my cropped image? 【发布时间】:2016-03-02 13:53:40 【问题描述】:

我对这个插件非常失望。我是 JS/Jquery 的菜鸟,但我的网站非常需要这个插件...... 所以我在这里找到了cropit:http://scottcheng.github.io/cropit/

我不知道如何在控制器中取回裁剪的图像并保存... 所以我的表格是:

<div class="form-group">
     form_label(form.image, 'Image', 'label_attr': 'class': 'col-sm-3 control-label')
      <div class="image-cropper">
           <!-- This is where the preview image is displayed -->
          <div class="row">
            <div class="col-sm-offset-2 col-sm-8">
              <div class="cropit-image-preview-container">
               <div class="cropit-image-preview"></div>
             </div>
           </div>
         </div> 
                <!-- This range input controls zoom -->
                    <!-- You can add additional elements here, e.g. the image icons -->
          <div class="row">
            <div class="col-sm-offset-4 col-sm-4">
              <input type="range" class="cropit-image-zoom-input" />
            </div>
          </div>
               form_errors(form.image) 

          <div class="row">    
            <div class="col-sm-4">
               form_widget(form.image) 
                <div class="select-image-btn">Select new image</div>
                <div class="send_image">Get Cropped image.</div>
            </div>
          </div>
      </div>
</div>

我的 Jquery 代码:

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript" src=" asset('js/cropit-master/dist/jquery.cropit.js') "></script>

<script>
 $(function () 
     $('.select-image-btn').click(function()
         $('.cropit-image-input').click();
    );


      var z = $('.image-cropper');
      z.cropit(
          exportZoom: 0.5,
          imageBackground: true,
          imageBackgroundBorderWidth: 15
      );
      $('.send_image').click(function() 
            var h =z.cropit('export');
            alert(h);
       );
   );
</script>

我的 Image.php 实体:

     public function getFile()
  
    return $this->file;
  

  public function setFile(UploadedFile $file = null)
  
    $decoded = urldecode($file);
    $exp = explode(';', $decoded);
    $exp = explode(':', $exp[0]);
    $data = array_pop($exp);
    $this->file = imagecreatefromstring($file);


    if (null !== $this->url) 
      $this->tempFilename = $this->url;

      $this->url = null;
      $this->alt = null;
    
  

  /**
   * @ORM\PrePersist()
   * @ORM\PreUpdate()
   */
  public function preUpload()
  

    if (null === $this->file) 
      return;
    


    $this->url = $this->file->guessExtension();


    $this->alt = $this->file->getClientOriginalName();
 

  /**
   * @ORM\PostPersist()
   * @ORM\PostUpdate()
   */
  public function upload()
  

    if (null === $this->file) 
      return;
    


    if (null !== $this->tempFilename) 
      $oldFile = $this->getUploadRootDir().'/'.$this->id.'.'.$this->tempFilename;
      if (file_exists($oldFile)) 
        unlink($oldFile);
      
    


    $this->file->move(
      $this->getUploadRootDir(), // Le répertoire de destination
      $this->id.'.'.$this->url   // Le nom du fichier à créer, ici « id.extension »
    );
  

  /**
   * @ORM\PreRemove()
   */
  public function preRemoveUpload()
  
    $this->tempFilename = $this->getUploadRootDir().'/'.$this->id.'.'.$this->url;
  

  /**
   * @ORM\PostRemove()
   */
  public function removeUpload()
  
    if (file_exists($this->tempFilename)) 
      // On supprime le fichier
      unlink($this->tempFilename);
    
  

  public function getUploadDir()
  
    // On retourne le chemin relatif vers l'image pour un navigateur
    return 'uploads/img';
  

  protected function getUploadRootDir()
  
    // On retourne le chemin relatif vers l'image pour notre code PHP
    return __DIR__.'/../../../../web/'.$this->getUploadDir();
  

  public function getWebPath()
  
    return $this->getUploadDir().'/'.$this->getId().'.'.$this->getUrl();
  

我看到了很多帖子,但没有什么对我有用,我不太明白。 所以有人可以帮我解释一下吗? 谢谢

已编辑:我的第一个方法

我的表单使用隐藏输入来保存 base64 数据:

 $('form').submit(function() 
        // Move cropped image data to hidden input
        var imageData = $('.image-cropper').cropit('export');
        $('.hidden-image-data').val(imageData);
      ;``

我的 Imagetype 带有一个文件输入来加载原始图像和隐藏输入来保存 base64 图像。

 public function buildForm(FormBuilderInterface $builder, array $options)
    
        $builder
            ->add('file', 'file', array(
                'attr' => array('class' => 'cropit-image-input')))
            ->add('file', 'hidden', array('attr' => array('class' => 'hidden-image-data')))

        ;
    

我的控制器还是一样的。

【问题讨论】:

问题是,使用任何这种 js 裁剪脚本,您都不会在 setFile 字段中获得 UploadedFile 对象。我使用模型数据转换器和自定义字段类型使其与 symfony 一起使用。 我知道我得到了 base64 图像,不是吗?你能告诉我你是怎么做到的吗? 是的。你会得到带有一些不相关前缀的base64。这个想法是使用hidden 字段和DataTransformer 将其转换为文件形式。抱歉,我不确定我可以分享源代码。 @Flushdrew,你能检查我的答案吗? 【参考方案1】:

我已经解决了。

另外使用VichUploaderBundle

@K-Phoen 响应对于指导解决方案非常有用。 VichUploaderBundle & Cropit - Pass base64 to a File instance

这是我的代码:

User.php,这个以及更多 VichUploaderBundle 设置look here

namespace Application\Sonata\UserBundle\Entity;

//...
use Vich\UploaderBundle\Mapping\Annotation as Vich;

/**
 * User
 *
 * ........
 * ........
 * @Vich\Uploadable
 * ........
 * ........
 * 
 */
class User extends BaseUser 

    /**
     * NOTE: This is not a mapped field of entity metadata, just a simple property.
     * 
     * @Vich\UploadableField(mapping="user_avatar", fileNameProperty="avatarName")
     * 
     * @var File
     */
    private $avatar;

    /**
     * @ORM\Column(type="string", length=255)
     *
     * @var string
     */
    private $avatarName;

    /**
     * @ORM\Column(type="datetime")
     *
     * @var \DateTime
     */
    private $updatedAt;

    //....


    /**
     * If manually uploading a file (i.e. not using Symfony Form) ensure an instance
     * of 'UploadedFile' is injected into this setter to trigger the  update. If this
     * bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
     * must be able to accept an instance of 'File' as the bundle will inject one here
     * during Doctrine hydration.
     *
     * @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
     */
    public function setAvatar(File $image = null) 
        $this->avatar= $image;

        if ($image) 
            // It is required that at least one field changes if you are using doctrine
            // otherwise the event listeners won't be called and the file is lost
            $this->updatedAt = new \DateTime('now');
        
    

    /**
     * @return File
     */
    public function getAvatar() 
        return $this->avatar;
    

    /**
     * @param string $avatarName
     */
    public function setAvatarName($avatarName) 
        $this->avatarName= $avatarName;
    

    /**
     * @return string
     */
    public function getAvatarName() 
        return $this->avatarName;
    


UserType.php

namespace AppBundle\Form;

//...
use Doctrine\Common\Persistence\ObjectManager;
use AppBundle\Form\DataTransformer\ImageStringToFileTransformer;

class UserType extends AbstractType 

    private $manager;

    public function __construct(ObjectManager $manager)
    
        $this->manager = $manager;
    

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options) 
        $builder                
            ->add('avatar', 'hidden', [
                'attr' => [
                    'class' => 'hidden-image-data'
                ]
            ])
            ->add('imagedata', 'file', [
                'mapped' => false,
                'required' => false,
                'attr' => [
                    'class' => 'cropit-image-input'
                ]
            ])
            //...
            ;

        $builder->get('avatar')
            ->addModelTransformer(new ImageStringToFileTransformer($this->manager));
    

    //...


ImageStringToFileTransformer.php,魔术到这里就完成了,我们将base64字符串转换为UploadedFile

namespace AppBundle\Form\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\HttpFoundation\File\UploadedFile;

/**
 * Description of ImageStringToFileTransformer
 *
 * @author Juanjo García
 */
class ImageStringToFileTransformer implements DataTransformerInterface 

    private $manager;

    public function __construct(ObjectManager $manager) 
        $this->manager = $manager;
    

    /**
     * Transforms a string (base64) to an object (File).
     *
     * @param  string $imageString
     * @return File|null
     * @throws TransformationFailedException if no object (File)
     */
    public function reverseTransform($imageString) 

        // no base64? It's optional, so that's ok       
        if (!$imageString) 
            return;
        

        preg_match('/data:([^;]*);base64,(.*)/', $imageString, $matches);

        $mimeType = $matches[1];
        $imagenDecodificada = base64_decode($matches[2]);
        $filePath = sys_get_temp_dir() . "/" . uniqid() . '.png';
        file_put_contents($filePath, $imagenDecodificada);

        $file = new UploadedFile($filePath, "user.png", $mimeType, null, null, true);

        if (null === $file) 
            // causes a validation error
            // this message is not shown to the user
            // see the invalid_message option
            throw new TransformationFailedException(sprintf(
                 'An issue with number "%s" does not exist!', $imageString
            ));
        

        return $file;
    

    /**
     * Transforms an object (File) to a string (base64).
     *
     * @param  File|null $file
     * @return string
     */
    public function transform($file) 
        return '';
    


services.yml

services:

    # datatransformer before saving to image
    app.form.type.user:
        class: AppBundle\Form\UserType
        arguments: 
            entityManager: "@doctrine.orm.entity_manager"
        tags:
            - 
                name: form.type

在我的树枝上, my_form.html.twig

<script src=" asset('jquery.js') "></script>
<script src=" asset('jquery.cropit.js') "></script>
<script src=" asset('jquery.custom.js') "></script>

% form_theme form with ['AppBundle:Forms:vich_cropit_fields.html.twig'] %

 form_start(form, 'action': path('the_path'), 'method': 'POST', 'multipart': true, 'attr': 'class': 'the_class', 'role': 'form' ) 
    <div class="image-editor">
        <div class="cropit-image-preview-container">
            <div class="cropit-image-preview"></div>
        </div>
         form_widget(form.avatar) 
         form_widget(form.imagedata)  
        <div class="image-size-label">
        Resize image
        </div>
        <input type="range" class="cropit-image-zoom-input">
        % if app.user.avatarName %
            <img src=" vich_uploader_asset(app.user, 'avatar') " id="current-avatar" class="hide" />
        % endif %
    </div>   

     form_rest(form)        

    <button type="submit" name="submit">Save</button>  

 form_end(form) 

初始化 Cropit,jquery.custom.js

(function ($) 

    $('.image-editor').cropit(
          exportZoom: 0.5,
          imageBackground: true,
          imageBackgroundBorderWidth: 50
      );

    $('.image-editor').cropit('imageSrc', $("#current-avatar").attr('src'));

    $('form').submit(function () 
        // Move cropped image data to hidden input
        var imageData = $('.image-editor').cropit('export');
        $('.hidden-image-data').val(imageData);
    );

).apply(this, [jQuery]);

由于我没有在任何地方找到解决方案的答案,我决定离开这里,为所有需要它的人。希望对您有所帮助。

【讨论】:

哦,我还没有看到这个答案!我将在我的代码中尝试它。感谢您花时间和解释! 嗨@jjgarcía 我需要您的帮助,请尝试在我的一个项目中使用您的解决方案。但没有成功,它不起作用。我可以调整图像大小并上传它,但保存图像路径的数据库表字段在实体保存后为空。我从那时起工作了大约 4 个月。我累了请帮帮我。对不起,如果我有一些错误,英语不是我的主要语言。 嗨@angel 您是否在您的实体定义中包含此行 * @Vich\Uploadable?你有什么错误吗? @jjgarcía 是的,我已经这样做了,但是没有用。我有同样的错误。也许我应该发布我的源代码来帮助我 @angel 好的,用你的代码创建一个 Gist,然后我尝试找到一种方法来检查它。【参考方案2】:

获取保存文件的路径:

<?php
public function getUploadedFilePath()

    return $this->getUploadRootDir().'/'.$this->id.'.'.$this->tempFilename;

尝试在 copit 页面上获取图像数据:

<script>
var h = $imageCropper.cropit('export', 
  type: 'image/jpeg',
  quality: .9,
  originalSize: true
);
</script>

【讨论】:

但是我的裁剪图像暂时没有保存。我的代码只是保存原始图像。这是我的大问题。 我不明白,因为当我单击“选择图像”div 或“获取裁剪图像”div 以获取 base64 数据时,什么也没发生……我的代码中是否有任何错误? 我在我的问题中编辑了我的 Jquery 和表单。所以现在“选择新图像正在工作,但我网站上的“获取裁剪图像”却没有。我在 JsFiddle 上尝试过,它可以工作,所以可能有我的脚本有冲突。可能是什么问题?我使用 bootstrap 和一个名为 clean-blog 的 bootstrap 模板。 如何将图像发送到服务器?你发送裁剪信息并且必须在php中再次裁剪图像(例如使用imagemagick)还是发送base64信息?请提供代码示例。 我在第一个问题的末尾用一些代码进行了编辑。谢谢

以上是关于Symfony2-Crop |如何取回我裁剪的图像?的主要内容,如果未能解决你的问题,请参考以下文章

裁剪像素缓冲区

如何选择图像的区域进行裁剪?

我想裁剪图像并输入在图像中查看。如何使用这种类型的裁剪从相机裁剪图像?

如何缩放 + 裁剪图像并在 imageview 上显示裁剪的图像

如何使用 jcrop 裁剪不同尺寸的图像

如何在不使用内部相机裁剪的情况下裁剪图像