【问题标题】:How to draw a shape using a piece of image in php如何在php中使用一张图像绘制形状
【发布时间】:2016-02-04 12:48:12
【问题描述】:

我需要使用一张图像创建一个框架图像。

例如:

用户将从后端上传一张图片:

现在我需要根据前端用户的要求在前端创建一个框架(用户将选择框架的高度和宽度,然后他将选择这个图像块),如下所示:

我没有办法做到这一点,我曾尝试通过 css 和 html canvas 做到这一点,但没有运气。

有人可以建议我如何通过使用 PHP 或 CSS 或 HTML 或 JavaScript 或任何方式来实现这一点。

您可以在此处查看工作示例,这实际上是我需要做的。

Create your own frame

【问题讨论】:

  • 使用 PHP,阅读 GD 或使用 HTML5 画布,如果你想操作图像客户端
  • 您可以使用 jquery ui 裁剪和调整图像大小来编辑图像,并在上传时将其用作背景图像或画布填充

标签: javascript php html css html5-canvas


【解决方案1】:

预处理图像至关重要

无论是由您手动完成,还是通过 GD 库以某种方式在运行中完成,您绝对至少需要拍摄您所收到的图像...

...然后裁剪并收紧它,使其像这样干净(边缘周围没有空白区域并且去除了凹口/切口):

然后你就有了一个你可以实际使用的图像。

否则,纯 CSS / JAVASCRIPT

注意:我不是在这里做 javascript。它将用于动态设置元素大小,如 html 中所示。

通常我会使用大量的 :before 和 ':after' 伪元素来保持 html 不那么混乱,但是由于您需要动态调整框架大小,所以我们需要使用一些嵌套的 div 元素来为对某些 div 元素(如果 javascript 可以访问这些元素或如果不需要动态调整大小,其中一些仍然是伪元素)至关重要的宽度和高度设置动态样式。

注意:到目前为止,我只在 Chrome 和 Firefox 中对此进行了测试。真正的旧浏览器肯定会惨遭失败。

/* implementation of framing */

    .frameit {
        /* width and height must be set dynamically by javascript see html */ 
        position: relative;
        box-sizing: border-box;
        overflow: hidden;
        padding: 20px; /* at least border size */
    }

    .frameit:before,
    .frameit:after,
    .frameit .sides > div,
    .frameit .corner > div {
        position: absolute;
        background-image: url(http://i.stack.imgur.com/vAgqj.jpg);
        background-size: 100% 20px; /* 100% and border size */
        height: 20px; /* equal to border width of frameit div */
    }

    .frameit:before {
        content: '';
        top: 0;
        left: 0;
        right: 0;
    }

    .frameit:after {
        content: '';
        bottom: 0;
        left: 0;
        right: 0;
    }

    .frameit .sides {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 1;
    }

    .frameit .sides > div {
        /* width must be set dynamically by javascript see html */ 
        height: 20px;
    }

    .frameit .sides > div:first-child {
        top: 0;
        left: 20px; /* border width */
        transform-origin: 0 0;
        transform: rotate(90deg);
    }

    .frameit .sides > div:last-child  {
        bottom: 0;
        right: 20px; /* border width */
        transform-origin: 100% 100%;
        transform: rotate(90deg);
    }

    .frameit .sides ~ .corner { /* all corners */
        position: absolute;
        z-index: 2;
        width: 29px; /* square root of ((border-width squared) x 2) round up */
        height: 29px; /* match width */
        overflow: hidden;
    }

    .frameit .TL {
        top: 0;
        left: 0;
        transform-origin: 0 0;
        transform: rotate(-45deg);
    }

    .frameit .TL > div {
        top: inherit;
        left: inherit;
        transform-origin: inherit;
        transform: rotate(45deg);
    }

    .frameit .TR {
        top: 0;
        right: 0;
        transform-origin: 100% 0;
        transform: rotate(45deg);
    }

    .frameit .TR > div {
        top: 0;
        right: 0;
        transform-origin: 100% 0;
        transform: rotate(-45deg);
    }

    .frameit .BR {
        bottom: 0;
        right: 0;
        transform-origin: 100% 100%;
        transform: rotate(-45deg);
    }

    .frameit .BR > div {
       bottom: inherit;
       right: inherit;
       transform-origin: inherit;
       transform: rotate(45deg);
    }

    .frameit .BL {
        bottom: 0;
        left: 0;
        transform-origin: 0 100%;
        transform: rotate(45deg);
    }

    .frameit .BL > div {
        bottom: inherit;
        left: inherit;
        transform-origin: inherit;
        transform: rotate(-45deg);
    }

    /* Optional shading to help define the joint */
    .frameit .sides > div:first-child:before,
    .frameit .sides > div:last-child:before {
       content: '';
       position: absolute;
       top: 0;
       right: 0;
       left: 0;
       bottom: 0;
       background-color: rgba(0,0,0,.07);
    }
<div class="frameit" style="width: 200px; height: 300px;">
   <!-- top and bottom and overall container 
        width and height assumed to be set by javacript by user
   -->
   <div class="sides">
     <!-- left and right sides 
        widths of the children are equal to HEIGHT of container and are 
        assumed to be set by javacript by user
     -->
     <div style="width: 300px;"></div>
     <div style="width: 300px;"></div>
   </div>
   <div class="TL corner"><!-- top left bevel --><div style="width: 200px;"></div></div>
   <div class="TR corner"><!-- top right bevel --><div style="width: 200px;"></div></div>
   <div class="BR corner"><!-- bottom right bevel --><div style="width: 200px;"></div></div>
   <div class="BL corner"><!-- bottom left bevel --><div style="width: 200px;"></div></div>
</div>

【讨论】:

  • 感谢您的帮助,它几乎解决了我的问题:)
  • 嗨 ScottS 我对此解决方案有疑问,请您帮忙。我已经改变了右侧,因为我需要向内所以我只是这样做 .frameit .sides > div:last-child {top: 0;右:0; transform: rotate(270deg);} 并且还改变了顶部,也需要在里面,我这样做 .frameit:before {transform: rotate(180deg);现在我无法将角落包裹起来。
【解决方案2】:

您在答案中发布的示例图像可能不适合用于生成框架。您应该为框架的水平和垂直侧获得 2 个不同的图像。斜面和边缘也可以是可以相应定位的不同图像。

.frame {
      position: relative;
      width: 500px;
      /*width of the frame*/
    }
    .horizontal-side {
      /*use a horizontal background that can repeat properly*/
      background: url(http://i.stack.imgur.com/vAgqj.jpg) repeat;
    }
    .horizontal-side {
      width: 500px;
      /*width of the frame*/
      height: 20px;
    }
    .vertical-side {
      /*use a vertical background that can repeat properly*/
      background: url(http://i.stack.imgur.com/vAgqj.jpg) repeat;
      width: 20px;
      height: 400px;
      /*height of the frame*/
    }
    .vertical-side.right {
      position: absolute;
      right: 0;
      top: 20px;
      /*same as the horizontal side's hight*/
    }
<div class="frame">
  <div class="horizontal-side top">

  </div>
  <div class="vertical-side left">

  </div>
  <div class="vertical-side right">

  </div>
  <div class="horizontal-side bottom">

  </div>
</div>

更新了来自@ScottS 回答的清理图像

【讨论】:

  • 感谢您的回答先生,这与我的解决方案非常接近。我已经尝试使用 css 使用剪辑路径创建角并旋转垂直边,这对我来说几乎很好。但是,是否可以仅使用一张图片(我希望使用任何 gd 库)来完成此操作,因为我只得到了一张我向您展示的图片。
【解决方案3】:

我已经尝试了很多通过 php 使用单个图像创建框架,但在 php 中没有找到任何解决方案。

在两个答案(Lucky Soni 的答案和 ScottS 的答案)的帮助下,我创建了一个脚本来完全满足我的要求(非常感谢两者)。

First I have created 4 images from single image while uploading:

$file = Input::file('image');
$destinationPath    = 'test/';
$filename           = time() . $file->getClientOriginalName();
$extension          = $file->getClientOriginalExtension();
$upload_success     = $file->move($destinationPath, $filename);

// This will create image for upper horizontal part
$im = new imagick(public_path().'/test/'.$filename);
$im->setImageFormat( "jpg" );
$topUperName = 'hr-uper-'.$filename;
$img_name = public_path().'/20*20/'.$topUperName;
$im->resizeImage(20,20,Imagick::FILTER_LANCZOS,1);
$im->writeImage($img_name);

// This will create image for vertical right part
$vrtRght = 'vrt-right-'.$filename;
$img_name = public_path().'/20*20/'.$vrtRght;
$im->rotateimage('', '90');
$im->writeImage($img_name);

// This will create image for bottom horizontal part
$topUperBtm = 'hr-btm-'.$filename;
$img_name = public_path().'/20*20/'.$topUperBtm;
$im->rotateimage('', '90');
$im->writeImage($img_name);

// This will create image for vertical left part
$vrtlft = 'vrt-left-'.$filename;
$img_name = public_path().'/20*20/'.$vrtlft;
$im->rotateimage('', '90');
$im->writeImage($img_name);

$im->clear();
$im->destroy();

unlink(public_path() . '/' . $filename);

HTML layout:

<div class="frame">
    <div class="horizontal-side top"></div>
    <div class="vertical-side left"></div>
    <div class="vertical-side right"></div>
    <div class="horizontal-side bottom"></div>
    <div class="right-top-corner corner-holder">
        <img class="right-top corner" src="<?php echo url(); ?>/20*20/hr-uper-1448949720a.jpg">
    </div>
    <div class="right-btm-corner corner-holder">
        <img class="right-btm" corner src="<?php echo url(); ?>/20*20/hr-btm-1448949720a.jpg">
    </div>
    <div class="left-top-corner corner-holder">
        <img  class="left-top corner" src="<?php echo url(); ?>/20*20/hr-uper-1448949720a.jpg">
    </div>
    <div class="left-btm-corner corner-holder">
        <img  class="left-btm corner" src="<?php echo url(); ?>/20*20/hr-btm-1448949720a.jpg">
    </div>
</div>

Styling:

.frame {
        position: relative;
        width: 500px; /* dynamic*/
        height: 500px; /* dynamic*/
    }

    .horizontal-side {
        width: 100%;
        height: 100px; /* height of image*/
        position: absolute;
    }
    .horizontal-side.top {
        background: url('<?php echo url(); ?>/20*20/hr-uper-1448949720a.jpg') repeat !important;
    }
    .horizontal-side.bottom {
        background: url('<?php echo url(); ?>/20*20/hr-btm-1448949720a.jpg') repeat !important;
    }
    .horizontal-side.top {
        top: 0 !important;
    }
    .horizontal-side.bottom {
        bottom: 0 !important;
    }
    .vertical-side {
        width: 100px !important; /* width of image*/
        height: 100% !important;
        z-index: 9 !important;
        position: absolute !important;
    }
    .vertical-side.left {
        left: 0 !important;
        background: url('<?php echo url(); ?>/20*20/vrt-left-1448949720a.jpg') repeat !important;
    }
    .vertical-side.right {
        right: 0;
        background: url('<?php echo url(); ?>/20*20/vrt-right-1448949720a.jpg') repeat !important;
    }
    .corner-holder {
        position: absolute !important;
        z-index: 9 !important;
    }
    .right-top-corner{
        right: 0px !important;
    }
    .right-btm-corner {
        bottom: 0 !important;
    }
    .left-top-corner{
        left: 0 !important;
    }
    .left-btm-corner{
        bottom: 0 !important;
        left: 0 !important;
    }

    .corner {
        height: 100px !important; /* corner height (size of image)*/
        width: 100px !important; /*  corner width (size of image)*/
    }
    .right-top {
        clip: polygon(100% 0, 0% 100%, 0 0) !important;
        -webkit-clip-path: polygon(100% 0, 0% 100%, 0 0) !important;
        -moz-clip-path: polygon(100% 0, 0% 100%, 0 0) !important;
        -ms-clip-path: polygon(100% 0, 0% 100%, 0 0) !important;
        -o-clip-path: polygon(100% 0, 0% 100%, 0 0) !important;
        clip-path: polygon(100% 0, 0% 100%, 0 0) !important;
    } 
    .right-btm{
        clip: polygon(0 100%, 0 0, 100% 100%) !important;
        -webkit-clip-path: polygon(0 100%, 0 0, 100% 100%) !important;
        -moz-clip-path: polygon(0 100%, 0 0, 100% 100%) !important;
        -ms-clip-path: polygon(0 100%, 0 0, 100% 100%) !important;
        -o-clip-path: polygon(0 100%, 0 0, 100% 100%) !important;
        clip-path: polygon(0 100%, 0 0, 100% 100%) !important;
    }
    .left-top{
        clip: polygon(100% 0, 0 0, 100% 100%) !important;   
        -webkit-clip-path: polygon(100% 0, 0 0, 100% 100%) !important;   
        -moz-clip-path: polygon(100% 0, 0 0, 100% 100%) !important;   
        -ms-clip-path: polygon(100% 0, 0 0, 100% 100%) !important;   
        -o-clip-path: polygon(100% 0, 0 0, 100% 100%) !important;   
        clip-path: polygon(100% 0, 0 0, 100% 100%) !important;   
    }
    .left-btm{
        clip: polygon(100% 0, 0 100%, 100% 100%) !important;   
        -webkit-clip-path: polygon(100% 0, 0 100%, 100% 100%) !important;   
        -moz-clip-path: polygon(100% 0, 0 100%, 100% 100%) !important;   
        -ms-clip-path: polygon(100% 0, 0 100%, 100% 100%) !important;   
        -o-clip-path: polygon(100% 0, 0 100%, 100% 100%) !important;   
        clip-path: polygon(100% 0, 0 100%, 100% 100%) !important;   
    }

现在我可以从任何类型的图像创建合适的框架

【讨论】:

    【解决方案4】:
    <?php
    header('Content-type: image/png');
    $png_image = imagecreate(300, 300);
    $grey = imagecolorallocate($png_image, 229, 229, 229);
    $green = imagecolorallocate($png_image, 128, 204, 204);
    imagefilltoborder($png_image, 0, 0, $grey, $grey);
    
    imagefilledrectangle ($png_image, 20, 20, 80, 80, $green);     // SQUARE
    imagefilledrectangle ($png_image, 100, 20, 280, 80, $green);   // RECTANGLE
    imagefilledellipse ($png_image, 50, 150, 75, 75, $green);      // CIRCLE
    imagefilledellipse ($png_image, 200, 150, 150, 75, $green);    // ELLIPSE
    
    $poly_points = array(150, 200, 100, 280, 200, 280);
    imagefilledpolygon ($png_image, $poly_points, 3, $green);      // POLYGON
    
    imagepng($png_image);
    imagedestroy($png_image);
    

    试试看

    sn-p 来自:http://www.phpforkids.com/php/php-gd-library-drawing-shapes.php

    【讨论】:

    • 这个方案我试过了,但是这个方案怎么用图片纹理
    • 与GD lib以外的问题无关
    • @Anshul Mishra 请看链接
    • @Jack Smith 请先完成需求,如果您认为给定的链接可以提供帮助,请创建一些演示并分享您的代码。
    【解决方案5】:

    我看过你的解决方案,这已经足够好了。但是我注意到一些事情,当我尝试增加高度和宽度时,它没有给出适当的结果。

    我尝试通过使用不同尺寸的图片来解决这个问题。

    $file = Input::file('image');
    $destinationPath    = 'test/';
    $filename           = time() . $file->getClientOriginalName();
    $extension          = $file->getClientOriginalExtension();
    $upload_success     = $file->move($destinationPath, $filename);
    
    // This will create image for upper horizontal part
    $im = new imagick(public_path().'/test/'.$filename);
    $im->setImageFormat( "jpg" );
    
    /** Here I have created 4 side images of 20*20 **/  
    $topUperName = 'hr-uper-'.$filename;
    $img_name = public_path().'/20*20/'.$topUperName;
    $im->resizeImage(20,20,Imagick::FILTER_LANCZOS,1);
    $im->writeImage($img_name);
    
    // This will create image for vertical right part
    $vrtRght = 'vrt-right-'.$filename;
    $img_name = public_path().'/20*20/'.$vrtRght;
    $im->rotateimage('', '90');
    $im->writeImage($img_name);
    
    // This will create image for bottom horizontal part
    $topUperBtm = 'hr-btm-'.$filename;
    $img_name = public_path().'/20*20/'.$topUperBtm;
    $im->rotateimage('', '90');
    $im->writeImage($img_name);
    
    // This will create image for vertical left part
    $vrtlft = 'vrt-left-'.$filename;
    $img_name = public_path().'/20*20/'.$vrtlft;
    $im->rotateimage('', '90');
    $im->writeImage($img_name);
    
    $im->clear();
    $im->destroy();
    
    
    /** Here I have created 4 side images of 30*30 **/
    // This will create image for upper horizontal part
    $im2 = new imagick(public_path().'/test/'.$filename);
    $im2->setImageFormat( "jpg" );
    
    $topUperName = 'hr-uper-'.$filename;
    $img_name = public_path().'/30*30/'.$topUperName;
    $im2->resizeImage(30,30,Imagick::FILTER_LANCZOS,1);
    $im2->writeImage($img_name);
    
    // This will create image for vertical right part
    $vrtRght = 'vrt-right-'.$filename;
    $img_name = public_path().'/30*30/'.$vrtRght;
    $im2->rotateimage('', '90');
    $im2->writeImage($img_name);
    
    // This will create image for bottom horizontal part
    $topUperBtm = 'hr-btm-'.$filename;
    $img_name = public_path().'/30*30/'.$topUperBtm;
    $im2->rotateimage('', '90');
    $im2->writeImage($img_name);
    
    // This will create image for vertical left part
    $vrtlft = 'vrt-left-'.$filename;
    $img_name = public_path().'/30*30/'.$vrtlft;
    $im2->rotateimage('', '90');
    $im2->writeImage($img_name);
    
    $im2->clear();
    $im2->destroy();
    
    /** Here I have created 4 side images of 40*40 **/
    // This will create image for upper horizontal part
    $im3 = new imagick(public_path().'/test/'.$filename);
    $im3->setImageFormat( "jpg" );
    
    $topUperName = 'hr-uper-'.$filename;
    $img_name = public_path().'/40*40/'.$topUperName;
    $im3->resizeImage(40,40,Imagick::FILTER_LANCZOS,1);
    $im3->writeImage($img_name);
    
    // This will create image for vertical right part
    $vrtRght = 'vrt-right-'.$filename;
    $img_name = public_path().'/40*40/'.$vrtRght;
    $im3->rotateimage('', '90');
    $im3->writeImage($img_name);
    
    // This will create image for bottom horizontal part
    $topUperBtm = 'hr-btm-'.$filename;
    $img_name = public_path().'/40*40/'.$topUperBtm;
    $im3->rotateimage('', '90');
    $im3->writeImage($img_name);
    
    // This will create image for vertical left part
    $vrtlft = 'vrt-left-'.$filename;
    $img_name = public_path().'/40*40/'.$vrtlft;
    $im3->rotateimage('', '90');
    $im3->writeImage($img_name);
    
    $im3->clear();
    $im3->destroy();
    
    
    /** Here I have created 4 side images of 50*50 **/
    // This will create image for upper horizontal part
    $im4 = new imagick(public_path().'/test/'.$filename);
    $im4->setImageFormat( "jpg" );
    
    $topUperName = 'hr-uper-'.$filename;
    $img_name = public_path().'/50*50/'.$topUperName;
    $im4->resizeImage(50,50,Imagick::FILTER_LANCZOS,1);
    $im4->writeImage($img_name);
    
    // This will create image for vertical right part
    $vrtRght = 'vrt-right-'.$filename;
    $img_name = public_path().'/50*50/'.$vrtRght;
    $im4->rotateimage('', '90');
    $im4->writeImage($img_name);
    
    // This will create image for bottom horizontal part
    $topUperBtm = 'hr-btm-'.$filename;
    $img_name = public_path().'/50*50/'.$topUperBtm;
    $im4->rotateimage('', '90');
    $im4->writeImage($img_name);
    
    // This will create image for vertical left part
    $vrtlft = 'vrt-left-'.$filename;
    $img_name = public_path().'/50*50/'.$vrtlft;
    $im4->rotateimage('', '90');
    $im4->writeImage($img_name);
    
    $im4->clear();
    $im4->destroy();
    
    unlink(public_path() . '/' . $filename);
    

    我已将图像的那部分裁剪为 4 种尺寸,以便我们可以在创建不同比例的框架时使用这些尺寸。

    For example if I am going to create a frame 1000*200, then it was breaking the css, because you were using a image of only 20*20 thick image in all sizes of frame.

    现在你只需要为所有尺寸的图片设置比例,例如:

    //you will get this from your ajax call
    $width = $_GET['width'];
    $width = $_GET['height'];
    
    if($width <= 200){
       $frameImage = 'path-of-your-20*20-image';
    }
    
    if($width > 200 && $width <= 500){
       $frameImage = 'path-of-your-30*30-image';
    }
    
    if($width > 500 && $width <= 700){
       $frameImage = 'path-of-your-40*40-image';
    }
    
    if($width > 700){
       $frameImage = 'path-of-your-50*50-image';
    }
    
    // you can set these variable as per your requirement. And then use this image path to create the html of your frame. If you need a big range of your frame then you can also crop and save image in more sizes while uploading.
    

    希望这对你有用

    【讨论】:

      猜你喜欢
      • 2014-01-12
      • 1970-01-01
      • 2012-01-12
      • 1970-01-01
      • 2011-09-09
      • 1970-01-01
      • 1970-01-01
      • 2020-10-24
      • 1970-01-01
      相关资源
      最近更新 更多