Componente de upload de imagens, com crop e rotação de imagem Componente de upload de imagens, com cropp e rotação de imagem. Bom dia a todos, no desenvolvimento de um novo projeto, me deparei com a necessidade de realizar o upload e manipulação de imagens, e por várias vezes tentei adaptar soluções expostas nos exemplos do framework, mas precisava de mais opções de configurações, como o crop, o giro e marca dágua, etc.....
MC
Componente de upload de imagens, com crop e rotação de imagem  
Componente de upload de imagens, com cropp e rotação de imagem.

Bom dia a todos, no desenvolvimento de um novo projeto, me deparei com a necessidade de realizar o upload e manipulação de imagens, e por várias vezes tentei adaptar soluções expostas nos exemplos do framework, mas precisava de mais opções de configurações, como o crop, o giro e marca dágua, etc..., sem falar que os celulares de hoje em dia tem alta definição de imagens, e isso com o tempo poderia se tornar um problema salvar imagens "tão grandes". pesquisando na internet, efetuei a compra do plugin "Slim Image Cropper", por cerca de 17 dólares, e com a ajuda do Nataniel, experiente programador e membro da adianti, que adaptou o mesmo, venho até vocês compartilhar e tentar de alguma forma contribuir nesse meio tão importante de comunicação.

Primeiramente quero deixar claro que o plugin é pago, e comercializado pela empresa codecanyon, deixo apenas nesse artigo, o link de compra, as instruções para configuração no frame, e os fontes de demonstração de uso.


1- primeiro passo, Efetuar a compra do plugin em https://pqina.nl/slim/.

2- Após a compra e download do plugin, descompactar o conteúdo em app/lib/slim

3- Copiar o arquivo TSlim.class.php para a pasta app/lib/widget/ (em anexo )

3- Em app/templates/theme4/libraries.html adicionar a linha <link href="app/lib/slim/css/slim.min.css?appver=400" rel="stylesheet" type="text/css" media="screen"><!--componente slim-->
(observar o template de uso)

4 - Os fontes de demostração de uso está nos 3 arquivos postados abaixo, Imagem.class.php(colocar em app/model), ImagemList.class.php(colocar em app/control), ImagemForm.class.php(colocar em app/control) , ( em anexo as instruções de uso )

5 - Criar a pasta images, na raiz do projeto ( onde serão salvas as imagens )

Para demostrar o uso do plugin, no banco de dados permission.db, crie uma tabela com o nome "imagem" com o campo chamado nome, que armazenará o caminho da imagem após o upload.

CREATE TABLE imagem ( id INTEGER PRIMARY KEY NOT NULL, nome varchar(100));



Abaixo a classe adaptada pelo Nataniel para o frame , que deverá ser copiada para app/lib/widget/


 
  1. <?php
  2. class TSlim extends TField implements AdiantiWidgetInterface
  3. {
  4. protected $value;
  5. public $container;
  6. public function __construct($name)
  7. {
  8. parent::__construct($name);
  9. //$this->id = 'slim_' . uniqid();
  10. $this->tag->type = 'file';
  11. $this->container = new TElement('div');
  12. $this->container->class = 'slim';
  13. $this->setDataProperties(['size'=>'640,640','label'=>'Upload imagem','button-confirm-label'=>'Confirmar',
  14. 'button-confirm-title'=>'Confirmar','button-cancel-label'=>'Cancelar',
  15. 'button-cancel-title'=>'Cancelar','button-edit-label'=>'Editar',
  16. 'button-edit-title'=>'Editar','button-remove-label'=>'Remover',
  17. 'button-remove-title'=>'Remover','button-rotate-label'=>'Girar',
  18. 'button-rotate-title'=>'Girar']);
  19. }
  20. public function setDataProperties($props)
  21. {
  22. foreach ($props as $prop => $val)
  23. {
  24. $this->container->{"data-{$prop}"} = $val;
  25. }
  26. }
  27. public function show()
  28. {
  29. $this->container->add($this->tag);
  30. if ($this->value)
  31. $this->container->add(new TImage($this->value));
  32. $js = TScript::create('',false);
  33. $js->src = 'app/lib/slim/js/slim.kickstart.min.js';
  34. $this->container->add($js);
  35. $this->container->show();
  36. }
  37. }
  38. ?>


Abaixo a classe de modelo, que deverá ser salva em app/model/

 
  1. <?php
  2. class Imagem extends TRecord
  3. {
  4. const TABLENAME = 'imagem';
  5. const PRIMARYKEY= 'id';
  6. const IDPOLICY = 'max'; // {max, serial}
  7. public function __construct($id = NULL, $callObjectLoad = TRUE)
  8. {
  9. parent::__construct($id, $callObjectLoad);
  10. parent::addAttribute('nome');
  11. }
  12. }?>



Abaixo a classe ImagemForm, que deverá ser salva na pasta app/control/.

 
  1. <?php
  2. class ImagemForm extends TPage
  3. {
  4. protected $form; // form
  5. public function __construct( $param )
  6. {
  7. parent::__construct();
  8. // creates the form
  9. $this->form = new TQuickForm('form_Imagem');
  10. $this->form->class = 'tform'; // change CSS class
  11. $this->form = new BootstrapFormWrapper($this->form);
  12. $this->form->style = 'display: table;width:100%'; // change style
  13. // define the form title
  14. $this->form->setFormTitle('Imagem');
  15. // create the form fields
  16. $id = new TEntry('id');
  17. $nome = new TSlim('nome');
  18. $nome->container->style = 'width:100%;height:240px;border:2px solid black';//tamanho do container do plugin no form
  19. $nome->setDataProperties(['label'=>'Upload imagem']);//aqui eu seto o nome do label
  20. //tamanho final no máximo 1500x1500 e proporção de 4:3 na janela de visualização
  21. $nome->setDataProperties(['size'=>'1500,1500','ratio'=>'4:3']);
  22. // add the fields
  23. $this->form->addQuickField('Id', $id, '100%' );
  24. $this->form->addQuickField('Nome', $nome, '100%' );
  25. if (!empty($id))
  26. {
  27. $id->setEditable(FALSE);
  28. }
  29. $nome->setDataProperties(['will-transform'=>'addWatermark']);
  30. //abaixo o código para inserir marca dágua
  31. $script = new TElement('script');
  32. $script->type = 'text/javascript';
  33. $javascript = "
  34. function addWatermark(data, ready) {
  35. // get the drawing context for the output image
  36. var ctx = data.output.image.getContext('2d');
  37. // draw our watermark on the center of the image
  38. var size = data.output.width / 40
  39. ctx.font = size + 'px sans-serif';
  40. var x = data.output.width * .5;
  41. var y = data.output.height * .9;
  42. var text = ctx.measureText('nome: nome que você escolher');
  43. var w = text.width * 1.15;
  44. var h = size * 1.75;
  45. ctx.fillStyle = 'rgba(0,0,0,.75)';
  46. ctx.fillRect(
  47. x - (w * .5),
  48. y - (h * .5),
  49. w, h
  50. );
  51. ctx.fillStyle = 'rgba(255,255,255,.9)';
  52. ctx.fillText(
  53. 'nome: nome que você escolher',
  54. x - (text.width * .5),
  55. y + (size * .35)
  56. );
  57. // continue saving the data
  58. ready(data);
  59. }
  60. ";
  61. $script->add($javascript);
  62. parent::add($script);
  63. // create the form actions
  64. $btn = $this->form->addQuickAction(_t('Save'), new TAction(array($this, 'onSave')), 'fa:floppy-o');
  65. $btn->class = 'btn btn-sm btn-primary';
  66. $btn2 = $this->form->addQuickAction(_t('New'), new TAction(array($this, 'onClear')), 'bs:plus-sign green');
  67. $btn3 = $this->form->addQuickAction( 'List' , new TAction(array('ImagemList', 'onClear')), 'fa:table blue' );
  68. // vertical box container
  69. $container = new TVBox;
  70. $container->style = 'width: 90%';
  71. // $container->add(new TXMLBreadCrumb('menu.xml', __CLASS__));
  72. $container->add(TPanelGroup::pack('Title', $this->form));
  73. parent::add($container);
  74. }
  75. public function onSave( $param )
  76. {
  77. try
  78. {
  79. TTransaction::open('permission'); // open a transaction
  80. /**
  81. if (empty($object->nome))
  82. {
  83. throw new Exception( 'O campo IMAGEM é obrigatório');
  84. }
  85. **/
  86. $this->form->validate(); // validate form data
  87. $object = new Imagem; // create an empty object
  88. $data = $this->form->getData(); // get form data as array
  89. $object->fromArray( (array) $data); // load the object with data
  90. $object2 = new Imagem($data->id); //objeto criado para testar se imagem foi repetida
  91. $images = Slim::getImages();
  92. // No image found under the supplied input name
  93. if ($images)
  94. {
  95. $image = $images[0];
  96. // save output data if set
  97. if (isset($image['output']['data']))
  98. {
  99. // Save the file
  100. $name = $image['output']['name'];
  101. // We'll use the output crop data
  102. $data = $image['output']['data'];
  103. //salva o arquivo na pasta images/ com o nome concatenado com o tempo
  104. $output = Slim::saveFile($data, time().'-'.$name, 'images/', false);
  105. //var_dump( $output );
  106. if( $object2->nome != $output )//teste de imagem repetida
  107. {
  108. if( file_exists ($object2->nome))// se existir apaga o anterior
  109. {
  110. unlink( $object2->nome ); //apaga
  111. }
  112. }
  113. $object->nome = $output['path'];//recebe o caminho para salvar
  114. }
  115. }
  116. else
  117. {
  118. $object2 = new Imagem($data->id);
  119. $object->nome = $object2->nome;
  120. }
  121. $object->store(); // save the object
  122. $this->form->setData($data); // fill form data
  123. TTransaction::close(); // close the transaction
  124. new TMessage('info', TAdiantiCoreTranslator::translate('Record saved'), new TAction(array('ImagemList', 'onClear')) );
  125. }
  126. catch (Exception $e) // in case of exception
  127. {
  128. new TMessage('error', $e->getMessage()); // shows the exception error message
  129. $this->form->setData( $this->form->getData() ); // keep form data
  130. TTransaction::rollback(); // undo all pending operations
  131. }
  132. }
  133. public function onClear( $param )
  134. {
  135. $this->form->clear(TRUE);
  136. }
  137. public function onEdit( $param )
  138. {
  139. try
  140. {
  141. if (isset($param['key']))
  142. {
  143. $key = $param['key']; // get the parameter $key
  144. TTransaction::open('permission'); // open a transaction
  145. $object = new Imagem($key); // instantiates the Active Record
  146. $this->form->setData($object); // fill the form
  147. TTransaction::close(); // close the transaction
  148. }
  149. else
  150. {
  151. $this->form->clear(TRUE);
  152. }
  153. }
  154. catch (Exception $e) // in case of exception
  155. {
  156. new TMessage('error', $e->getMessage()); // shows the exception error message
  157. TTransaction::rollback(); // undo all pending operations
  158. }
  159. }
  160. }
  161. ?>



Abaixo a grid de listagem, que deverá ser salva na pasta app/control

 
  1. <?php
  2. class ImagemList extends TStandardList
  3. {
  4. protected $form; // registration form
  5. protected $datagrid; // listing
  6. protected $pageNavigation;
  7. protected $formgrid;
  8. protected $deleteButton;
  9. protected $transformCallback;
  10. public function __construct()
  11. {
  12. parent::__construct();
  13. parent::setDatabase('permission'); // defines the database
  14. parent::setActiveRecord('Imagem'); // defines the active record
  15. parent::setDefaultOrder('id', 'asc'); // defines the default order
  16. // parent::setCriteria($criteria) // define a standard filter
  17. parent::addFilterField('id', 'like', 'id'); // filterField, operator, formField
  18. parent::addFilterField('nome', 'like', 'nome'); // filterField, operator, formField
  19. // creates the form
  20. $this->form = new TQuickForm('form_search_Imagem');
  21. $this->form->class = 'tform'; // change CSS class
  22. $this->form = new BootstrapFormWrapper($this->form);
  23. $this->form->style = 'display: table;width:100%'; // change style
  24. $this->form->setFormTitle('Imagem');
  25. // create the form fields
  26. $id = new TEntry('id');
  27. $nome = new TEntry('nome');
  28. // add the fields
  29. //$this->form->addQuickField('Id', $id, '100%' );
  30. $this->form->addQuickField('Nome', $nome, '100%' );
  31. // keep the form filled during navigation with session data
  32. $this->form->setData( TSession::getValue('Imagem_filter_data') );
  33. // add the search form actions
  34. $btn = $this->form->addQuickAction(_t('Find'), new TAction(array($this, 'onSearch')), 'fa:search');
  35. $btn->class = 'btn btn-sm btn-primary';
  36. $this->form->addQuickAction(_t('New'), new TAction(array('ImagemForm', 'onEdit')), 'bs:plus-sign green');
  37. // creates a DataGrid
  38. $this->datagrid = new TDataGrid;
  39. $this->datagrid = new BootstrapDatagridWrapper($this->datagrid);
  40. $this->datagrid->style = 'width: 100%';
  41. $this->datagrid->datatable = 'true';
  42. // creates the datagrid columns
  43. $column_id = new TDataGridColumn('id', 'Id', 'left');
  44. $column_nome = new TDataGridColumn('nome', 'Nome', 'left');
  45. // define the transformer method over image
  46. //função para mostrar a imagem no grid
  47. $column_nome->setTransformer( function($image) {
  48. $imagem= new TImage($image);
  49. $imagem->style='width:100px';//tamanho da imagem no grid
  50. return $imagem;
  51. });
  52. // add the columns to the DataGrid
  53. $this->datagrid->addColumn($column_id);
  54. $this->datagrid->addColumn($column_nome);
  55. // create EDIT action
  56. $action_edit = new TDataGridAction(array('ImagemForm', 'onEdit'));
  57. //$action_edit->setUseButton(TRUE);
  58. //$action_edit->setButtonClass('btn btn-default');
  59. $action_edit->setLabel(_t('Edit'));
  60. $action_edit->setImage('fa:pencil-square-o blue fa-lg');
  61. $action_edit->setField('id');
  62. $this->datagrid->addAction($action_edit);
  63. // create the datagrid model
  64. $this->datagrid->createModel();
  65. // create the page navigation
  66. $this->pageNavigation = new TPageNavigation;
  67. $this->pageNavigation->setAction(new TAction(array($this, 'onReload')));
  68. $this->pageNavigation->setWidth($this->datagrid->getWidth());
  69. // vertical box container
  70. $container = new TVBox;
  71. $container->style = 'width: 90%';
  72. // $container->add(new TXMLBreadCrumb('menu.xml', __CLASS__));
  73. $container->add(TPanelGroup::pack('Imagem', $this->form));
  74. $container->add(TPanelGroup::pack('', $this->datagrid, $this->pageNavigation));
  75. parent::add($container);
  76. }
  77. public function onClear( $param )
  78. {
  79. $this->form->clear(TRUE);
  80. }
  81. }
  82. ?>




No exemplo acima, utilizei o template 4

Os arquivos podem ser baixados no formato .zip no link em anexo, eles contem as classes citadas acima, e as instruções de uso;

Podem também ser visualizados nos links abaixo:

https://ibb.co/fCVNST
imagizer.imageshack.us/a/img923/3059/WHqFqZ.gif
https://i.imgur.com/ewxHm4C.gifv
https://uploaddeimagens.com.br/imagens/amostra-gif-33f5ddd4-ed6f-463a-8dfb-f79263717155

Espero de alguma forma estar contribuindo com todos que gostarem deste componente, fiquem a vontade em postarem perguntas, boa sorte a todos.


Curso Dominando o Adianti Framework

O material mais completo de treinamento do Framework.
Curso em vídeo aulas + Livro completo + Códigos fontes do projeto ERPHouse.
Conteúdo Atualizado!


Dominando o Adianti Framework Quero me inscrever agora!

Comentários (7)


MC

Para quem quiser testar o componente, segue o link:

miullerfc.acessotemporario.net/index.php?class=ImagemList&method
DS

parabéns !!!

LJ

Muito Legal, vou experimentar !!!
MZ

Boa noite.
Estou tentando usar este componente porem algumas duvidas surgem. 1 Tem como forçar o redimensionamento da imagem no tamanho que preciso?
2 O mesmo também esta a gerar um erro.

Fatal error: Uncaught Error: Class 'Slim' not found in C:wamp64wwwRealEstate2admappcontrolCorretoresForm.class.php on line 102
( ! ) Error: Class 'Slim' not found in C:wamp64wwwRealEstate2admappcontrolCorretoresForm.class.php on line 102

Não sei porque raios ele faz isso.
a linha 102 do código se refere há $images = Slim::getImages(); como tem no exemplo original
Segue código completo abaixo.
 
  1. <?php
  2. /**
  3. * CorretoresForm Registration
  4. * @author <your name here>
  5. */
  6. class CorretoresForm extends TPage
  7. {
  8. protected $form; // form
  9. use Adianti\Base\AdiantiStandardFormTrait; // Standard form methods
  10. /**
  11. * Class constructor
  12. * Creates the page and the registration form
  13. */
  14. function __construct()
  15. {
  16. parent::__construct();
  17. $this->setDatabase('RealState2'); // defines the database
  18. $this->setActiveRecord('Corretores'); // defines the active record
  19. // creates the form
  20. $this->form = new BootstrapFormBuilder('form_Corretores');
  21. $this->form->setFormTitle('Corretores');
  22. // create the form fields
  23. $ID = new TEntry('ID');
  24. $Foto_Corretor = new TSlim('Foto_Corretor');
  25. $Foto_Corretor->container->style = 'width:100%;height:440px;border:2px solid black';//tamanho do container do plugin no form
  26. $Foto_Corretor->setDataProperties(['label'=>'Upload imagem']);//aqui eu seto o nome do label
  27. //tamanho final no máximo 1500x1500 e proporção de 4:3 na janela de visualização
  28. $Foto_Corretor->setDataProperties(['size'=>'190,190','ratio'=>'4:3']);
  29. $Nome_Corretor = new TEntry('Nome_Corretor');
  30. $Descricao = new TText('Descricao');
  31. $email = new TEntry('email');
  32. $Telefone = new TEntry('Telefone');
  33. // add the fields
  34. $this->form->addFields( [ new TLabel('Id') ], [ $ID ] );
  35. $this->form->addFields( [ new TLabel('Foto Corretor') ], [ $Foto_Corretor ] );
  36. $this->form->addFields( [ new TLabel('Nome Corretor') ], [ $Nome_Corretor ] );
  37. $this->form->addFields( [ new TLabel('Descricao') ], [ $Descricao ] );
  38. $this->form->addFields( [ new TLabel('Email') ], [ $email ] );
  39. $this->form->addFields( [ new TLabel('Telefone') ], [ $Telefone ] );
  40. // set sizes
  41. $ID->setSize('100%');
  42. $Foto_Corretor->setSize('100%');
  43. $Nome_Corretor->setSize('100%');
  44. $Descricao->setSize('100%');
  45. $email->setSize('100%');
  46. $Telefone->setSize('100%');
  47. if (!empty($ID))
  48. {
  49. $ID->setEditable(FALSE);
  50. }
  51. /** samples
  52. $fieldX->addValidation( 'Field X', new TRequiredValidator ); // add validation
  53. $fieldX->setSize( '100%' ); // set size
  54. **/
  55. // create the form actions
  56. $btn = $this->form->addAction(_t('Save'), new TAction([$this, 'onSave']), 'fa:floppy-o');
  57. $btn->class = 'btn btn-sm btn-primary';
  58. $this->form->addAction(_t('New'), new TAction([$this, 'onEdit']), 'fa:eraser red');
  59. // vertical box container
  60. $container = new TVBox;
  61. $container->style = 'width: 90%';
  62. // $container->add(new TXMLBreadCrumb('menu.xml', __CLASS__));
  63. $container->add($this->form);
  64. parent::add($container);
  65. }
  66. public function onSave( $param )
  67. {
  68. try
  69. {
  70. TTransaction::open('RealState2'); // open a transaction
  71. /**
  72. if (empty($object->nome))
  73. {
  74. throw new Exception( 'O campo IMAGEM é obrigatório');
  75. }
  76. **/
  77. $this->form->validate(); // validate form data
  78. $object = new Corretores; // create an empty object
  79. $data = $this->form->getData(); // get form data as array
  80. $object->fromArray( (array) $data); // load the object with data
  81. $images = Slim::getImages();
  82. // No image found under the supplied input name
  83. if ($images)
  84. {
  85. $image = $images[0];
  86. // save output data if set
  87. if (isset($image['output']['data']))
  88. {
  89. // Save the file
  90. $name = $image['output']['name'];
  91. // We'll use the output crop data
  92. $data = $image['output']['data'];
  93. //salva o arquivo na pasta images/ com o nome concatenado com o tempo
  94. $output = Slim::saveFile($data, time().'-'.$name, 'images/', false);
  95. //var_dump( $output );
  96. if( $object2->nome != $output )//teste de imagem repetida
  97. {
  98. if( file_exists ($object2->nome))// se existir apaga o anterior
  99. {
  100. unlink( $object2->nome ); //apaga
  101. }
  102. }
  103. $object->nome = $output['path'];//recebe o caminho para salvar
  104. }
  105. }
  106. else
  107. {
  108. $object2 = new Imagem($data->id);
  109. $object->nome = $object2->nome;
  110. }
  111. $object->store(); // save the object
  112. $this->form->setData($data); // fill form data
  113. TTransaction::close(); // close the transaction
  114. new TMessage('info', TAdiantiCoreTranslator::translate('Record saved'), new TAction(array('ImagemList', 'onClear')) );
  115. }
  116. catch (Exception $e) // in case of exception
  117. {
  118. new TMessage('error', $e->getMessage()); // shows the exception error message
  119. $this->form->setData( $this->form->getData() ); // keep form data
  120. TTransaction::rollback(); // undo all pending operations
  121. }
  122. }
  123. }
  124. </your>
AG

Ola amigo comprei este componente slim mas estou com problemas em salvar no servidor já fiz vários teste permissão de pasta etc. Se puder me ajudar por favor com este erro: error: connection falied. Este erro ocorro quando estou tentando salvar o arquivo com slim. Obrigado Anderson
WS

Para corrigir o erro

Fatal error: Uncaught Error: Class 'Slim' not found in C:wamp64wwwRealEstate2admappcontrolCorretoresForm.class.php on line 102
( ! ) Error: Class 'Slim' not found in C:wamp64wwwRealEstate2admappcontrolCorretoresForm.class.php on line 102

Renomeie o arquivo da pasta
app\lib\slim\slim.php
para
app\lib\slim\Slim.php


O slim está com "s" minusculo.
MC

Caso alguém tenha alguma dúvida, deixe seu email de contato.