使上传区域上的选定区域透明

Posted

技术标签:

【中文标题】使上传区域上的选定区域透明【英文标题】:Make selected area on uploaded area transparent 【发布时间】:2014-10-21 17:55:55 【问题描述】:

我正在从表单(在 wordpress 中)上传图像,并且我希望允许用户使用铅笔工具在某个区域周围画一条线。想想 Photoshop 中的套索工具。所以用户基本上可以“标记”要修改的区域。

我希望看到的是,是否可以使用 imagemagik、gd 或客户端 JS 库来找到该选定区域,并将其中的所有内容转换为透明。

这是一个示例图像。假设一个人想要上传这张图片,并使用上传器,他们标记了一条红线来选择他们想要透明的内容。

所以红线里面的图片,应该被imagemagik/gd/client js检测到,里面的东西都是透明的。

我找不到任何东西来看看这是否可能。在服务器上,我使用的是 php,因此如果可能的话,我可以使用 imgmagik/gd 进行操作。所以我需要知道这些是否可以占据红色区域的内部并使其透明。但我更愿意,如果我能找到一个客户端 JS 库或 jquery 插件,那将让最终用户通过图像上传实用程序在客户端执行此操作。然后最后上传最终修改后的图片。

非常感谢您对此的任何帮助或意见。

【问题讨论】:

【参考方案1】:

有一些工具可以使用 html5 的画布和 ImageMagick。以下是我将如何实施解决方案。

显示上传的图片,顶部带有canvas 元素。使用 javascript 匹配宽度和高度,并绑定事件侦听器以收集鼠标移动。

var MyDrawing = 
  // A new drawing event. Init points & start canvas path (for feedback)
  "start" : function(evt) 
    var point = [evt.layerX, evt.layerY];
    var ctx = this.getContext("2d");
    ctx.beginPath();
    ctx.lineWidth = "2";
    ctx.strokeStyle = "red";
    ctx.moveTo(point[0], point[1]);
    this.points = [point];
  ,
  "update" : function(evt) 
    if(this.points) 
      this.getContext("2d").lineTo([evt.layerX, evt.layerY]);
      this.points.push([evt.layerX, evt.layerY]); // Collect latest point
    
  ,
  "end" : function(evt) 
    var ctx = this.getContext("2d");
    ctx.lineTo(evt.layerX, evt.layerY);
    ctx.closePath();
    ctx.stroke();
    this.points.push([evt.layerX, evt.layerY])
    // Send points to server via ajax
    myAjaxFunctionHere(this.points);
  

var c = document.getElementById("canvas");
c.addEventListener("mousedown", MyDrawing.start, false);
c.addEventListener("mousemove", MyDrawing.update, false);
c.addEventListener("mouseup", MyDrawing.end, false);

不是最好的,但它会给用户一些反馈。

在后端,将给定点归一化为 (x,y) 关联元组的列表。

// Example of what ImagickDraw is expecting. 
$points = array(
             array('x' => 193, 'y' => 103),
             array('x' => 192, 'y' => 102),
             // ....
          );

此时,您可以绘制一个图像蒙版,并将其应用于带有Imagick::compositeImage 的图像。或者使用Chroma Key 颜色直接在图像上绘制并切换为透明度。

$img = new Imagick('/path/to/uploaded/image.png'); // Load image
$chromaKey = new ImagickPixel('#6BFD00');          // Define Chroma
$draw = new ImagickDraw();                         //
$draw->setFillColor($chromaKey);                   // Fill with Chroma
$draw->polygon($points);                           // Draw Point
$img->drawImage($draw);                            // Apply to image
$img->paintTransparentImage($chromaKey, 0.0, 0.1); // Swap Chroma with transparent
$img->writeImage('/path/to/generated/image.png');  // Save to disk

【讨论】:

【参考方案2】:

你可以用 ImageMagick 做到这一点...

首先你让所有不是红色的都变成黑色:

convert lion.jpg -fill black -fuzz 20% +opaque red out.jpg

然后你把它变成黑白,并使用一个阈值来强制红色变成白色:

convert lion.jpg -fill black -fuzz 20% +opaque red -colorspace gray -threshold 5% out.jpg

现在你从左上角 (0,0) 开始用白色填充图像:

convert out.jpg -fill white -draw 'color 0,0 floodfill' new.jpg

然后,您使用该黑白图像作为原始狮子图像的透明蒙版,并在一个命令中执行所有处理步骤:

convert lion.jpg \
    \( +clone -fill black -fuzz 20% +opaque red -colorspace gray -threshold 5% -fill white -draw 'color 0,0 floodfill' \) -compose copy-opacity -composite out.png

这给出了这个:

【讨论】:

以上是关于使上传区域上的选定区域透明的主要内容,如果未能解决你的问题,请参考以下文章

如何判断屏幕上的选定区域包含文本?

Flutter:使剪切区域透明以滚动 ListView

在html页面里面制作一个上传图片的区域,就是点那个区域,就能上传照片,这个html代码应该怎么写?

是否不可能在与 s3 存储桶区域不同的区域上传文件? (IllegalLocationConstraintException)

as3 图片透明区域不接受鼠标事件的工具类

通过保留透明区域和移除彩色区域来使用 UIImage 遮罩 UIView