【问题标题】:How can you dynamically put different patterns on images in a webpage .如何在网页中的图像上动态放置不同的图案。
【发布时间】:2010-12-12 22:05:26
【问题描述】:

我有

  1. 一堆织物图案(简单的jpg文件)
  2. 字母表中每个字母的图像(空白背景)

我本质上想要一个类似这样的页面: http://www.craftcuts.com/hand-painted-wooden-letters-single-patterns.html

但我希望用户能够:

  1. 输入名称
  2. 选择一种模式(其中一个 jpg 文件)

然后让它以该模式显示该名称。

显然,我可以为每个字母组合创建单独的 jpg(现在我为每个带有白色背景颜色的字母创建一个 jpg)和图案,但我想知道是否有更优雅的编码方式它动态地将一个图像放在另一个字母上。


编辑: 在我最初的帖子中,我认为这必须是前端的东西(javascript),但如果它让它变得更容易(正如一些人问什么是后端),我的后端是一个 asp.net-mvc,所以如果有一些解决方案可以在服务器端构建它并发送到客户端,我也很乐意使用它。

【问题讨论】:

  • 您是否需要在纯 html 中执行此操作,因为您的示例显示了生成的图像。
  • 你是什么意思。 .它只需要最终出现在一个网站上,所以只要它的动态以某种方式运行,它就会起作用
  • 闪存是一种选择吗?因为我很肯定这会给你在排版和抗锯齿方面最好的结果。
  • 确定。 .任何可以完成工作的东西:)

标签: html asp.net-mvc image dhtml jpeg


【解决方案1】:

通过 Javascript 做到这一点的最简单方法可能是为每个字母设置一个图像掩码并将其应用到图案之上。通过图像蒙版,我的意思是一个完全黑色(或白色,或任何你喜欢的)的简单图像,带有字母形状的“切掉”透明部分。您可以简单地将其覆盖在模式文件上以获得想要的效果。

<div style="background: url(pattern.jpg)">
    <img src="letter_a.png" />
</div>

您可以动态更改img srcdiv background url 以切换模式和字母。您还可以根据用户输入动态创建新的divs

请注意,由于透明的 PNG,这在 IE6 中不会很容易工作。

或者,您可以使用 gd 之类的东西在服务器上动态生成图像,这会涉及更多一点,但最终会更灵活。

【讨论】:

  • 我不太关注这里。你有任何链接可以显示这方面的例子吗?
  • 1.将图案放在背景中。 2. 将“剪下”的图像放在顶部。 3. 通过“切口”中的孔查看图案。这里有一些相关的例子:ifohdesigns.com/blog/tutorials/transparent-png-mask
  • 虽然这种方式和透明的 png 确实提供了一种干净灵活的方式,但它不允许您使用如示例中所示的各种装饰字母,其中字母不仅在图案上不同,而且在形状上也不同好吧。
  • @richard 嗯?制作不同的字母怎么样? letter_a_helvetica.png, letter_a_courier.png...?您的建议将成倍增加您需要制作的组合数量(字母 * 字体 * 图案),这正是 OP 不想做的。根据我的建议,您只需为每种字体(字母 * 字体 + 图案)制作一组新字母。正如我所说,最佳方法当然是使用图像处理库完全自动生成字母/字体/图案,但它有自己的缺陷,并且是一种更先进的技术。
【解决方案2】:

您可以使用 ImageMagick 库来制作您和您的用户心中渴望的叠加的任意组合。这样一来,您就不再局限于可以通过 CSS 实现的简单事物。

ImageMagick examples

【讨论】:

  • 你是否建议我在链接中使用合成图像?
  • 类似的东西。我用ImageMagick实现了加水印,和这个很相似。
  • @oo:Artem 建议您使用 ImageMagick 在服务器上生成图像,大概是在用户请求文本和图案的某种组合之后。这可以通过 ImageMagick 轻松完成。
  • 听起来比透明遮罩解决方案要复杂一些。
  • +1 用于使用 ImageMagick - 在某些项目中也是如此。它在几乎任何服务器环境中都超级强大且易于使用。
【解决方案3】:

为了让用户能够输入自己的姓名,您需要一个文本字段。您还需要一个按钮来触发 Javascript 函数,该函数检查文本字段的值并呈现字母图像。

您可以使用以下代码来创建字母。您将需要一个带有 id 'textfield' 的文本字段和一个 div 来呈现带有 id 'output' 的结果,当然您可以更改它。我建议使用 select 元素来存储模式选项(本例中为#patternChooser)

function renderName()
{
    // Get the name to be rendered and the chosen pattern
    var text = document.getElementById('textfield').value;
    var pattern = document.getElementById('patternChooser').value;

    // Iterate over the name and create an element for each letter
    for(i = 0; i < text.length; i++)
    {
        var letter = document.createElement('div');
        letter.style.backgroundImage = 'url(' + pattern + '_' + text[i] + ')';

        document.getElementById('output').appendChild(letter);
    }
}

您可以使用以下 CSS 对字母应用一些定位(调整图片的宽度和高度):

#output div
{
    margin-left: 10px;
    width: 50px;
    height: 100px;
    float: left;
}

您需要将图像命名为:flowerpattern_a.png、brickpattern_j.png 等。

如果您希望字母实时显示,您可以使用 Javascript 的 onkeyup() 触发一个函数,该函数检查文本字段值的最后一个字符并为其创建一个元素。

精灵

您还可以使用精灵来提高性能。将字母的所有图像放入一张图像中。您将此图像设置为每个字母的背景。 快速阅读 CSS 精灵:http://css-tricks.com/css-sprites/ 您可以在上面的 CSS sn-p 中添加background-image: url(sprite.png);。 您需要设置字母的背景位置(letter.style.background-position = '100px 200px'

,而不仅仅是使用 Javascript 设置 backgroundImage

字体嵌入

如果您要使用字体:有很多字体嵌入选项,例如 TypefaceCufon。我觉得最愉快的工作是使用font-face。它速度很快,并且文本的行为与任何其他文本一样。

如果您有 .TTF Truetype 字体,则需要将字体转换为 .EOT 以用于 Internet Explorer。您还可以添加 SVG 字体以实现完整的浏览器覆盖。这实际上非常简单:您只需将以下 sn-p 添加到样式表的顶部,如下所示:

@font-face {
  font-family: 'GothicCustom';
    src: url("LeagueGothic.eot");
    src: local('League Gothic'),
       url("LeagueGothic.svg#lg") format('svg'),
       url("LeagueGothic.otf") format('opentype');
}

这种技术的优势在于它易于使用,并且您可以完全控制呈现的文本,就像您网站上的任何其他文本一样。您可以设置字体大小、字母间距等Here's a good read about font-face font embedding。 您可以使用Microsoft WEFTTTF2EOT 创建.EOT 字体。

例如,您的代码可能如下所示。

Javascript

function renderName()
{
    // Get the name to be rendered and the chosen pattern
    var text = document.getElementById('textfield').value;
    var pattern = document.getElementById('patternChooser').value;

    // Render the text with a class
    for(i = 0; i < text.length; i++)
    {
        var output = document.getElementById('output');

        output.style.fontFamily = pattern;
        output.innerHTML = text;
    }
}

HTML

<form>
    <input id="textfield" type="text" />

    <select id="patternChooser">
        <option>Flowers</option>
        <option>Brick</option>
        <option>Decorative</option>
    </select>

    <input type="button" onclick="renderName()" />
</form>

<div id="output"></div>

CSS

@font-face {
  font-family: 'Decorative';
    src: url("decorative.eot");
    src: local('Decorative'),
       url("Decorative.svg#lg") format('svg'),
       url("Decorative.otf") format('opentype');
}

现在唯一剩下的就是转换字体并将它们导入到您的样式表中。

当然,您可以选择使用任何其他字体嵌入方法。 Here's an article about font-embedding options 但快速的 Google 也会向您显示选项。

【讨论】:

  • 你不是在暗示,通过添加精灵,OP 试图找到比它更优雅的解决方案吗?
  • 我想我同意。 .在您的示例中,我是否需要预先设置字母和图案的每种组合?
  • 在本例中,您需要为图案中的每个字母保存一个 png 或为每个图案创建一个精灵。我添加了字体嵌入选项,您只需提供字体并将它们导入样式表。
【解决方案4】:

阅读下面的链接,您将找到动态加载器详细信息以及示例 http://thecodecentral.com/2008/02/21/a-useful-javascript-image-loader

【讨论】:

    【解决方案5】:

    如果允许您在后端使用某些东西,这里有一个 java 解决方案。您只需要输入字母时使用的字体 (name.ttf),但我假设您拥有它:

    (这是在 servlet doGet 方法中)

    String text = "一封信,或者这里的任何文字"; 文件纹理 = 新文件(patternTexturePath); 文件字体文件 = 新文件(文件路径); 字体字体 = Font.createFont(Font.TRUETYPE_FONT, fontFile); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); ge.registerFont(字体); BufferedImage buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); g2 = buffer.createGraphics(); g2.clearRect(0, 0, 宽度, 高度); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); FontRenderContext fc = g2.getFontRenderContext(); Rectangle2D bounds = font.getStringBounds(text, fc); AttributedString attrStr = new AttributedString(text); 矩形 r = new Rectangle(0, 0, width, height); attrStr.addAttribute(TextAttribute.FOREGROUND, new TexturePaint(ImageIO.read(texture), r)); attrStr.addAttribute(TextAttribute.FONT, 字体); g2.drawString(attrStr.getIterator(), 0, (int) -bounds.getY()); response.setContentType("图片/png"); ImageIO.write(buffer, "png", response.getOutputStream()); response.getOutputStream().close();

    【讨论】:

      【解决方案6】:

      您可以使用 CSS 将背景图像应用于图像,然后为字母使用大量透明的 .png 图像。

      我模拟了它:

      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
      <html>
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
      <title>Untitled Document</title>
      
      <style type="text/css">
      
       img.leaves
       {
          background:url("leaves.png");
       }
       img.lights
       {
          background:url("lights.png");
       }
      
      </style>
      
      <script type="text/javascript">
      
      function makeText()
      {
          var text = document.getElementById('text').value.toUpperCase();
          var pattern = document.getElementById('pattern').value;
      
          for(var i=0; i<text.length; i++)
          {
              var img = document.createElement('img');
              img.src=text[i]+'.png';
              img.className=pattern;
              document.getElementById('textArea').appendChild(img);
          }
      
          return false;
      }
      
      </script>
      
      </head>
      
      <body>
      
      <form onsubmit="return makeText();">
      <p><label for="text">Enter your text</label> <input type="text" name="text" id="text" size="20"></p>
      <p><label for="pattern">Choose a pattern</label> <select id="pattern"><option value="leaves">Leaves</option><option value="lights">Lights</option></select></p>
      <p><input type="submit" value="Make!"></p>
      </form>
      
      <div id="textArea"></div>
      
      </body>
      </html>
      

      你也可以see it in action

      alt text http://www.subdimension.co.uk/files/1/SO/A.png

      alt text http://www.subdimension.co.uk/files/1/SO/leaves.png 和其中一种背景图案。

      我厌倦了G,所以你只能写包含字母ag的单词,它也有点懒,它只写大写并且只有2个模式但希望它应该足以给你一个想法

      【讨论】:

      • 是的,这完全是我刚刚使用负面掩码所写的内容。这是最灵活的方法,您可以通过读取目录列表轻松生成模式列表。如果您需要在 IE6 中完全兼容 png,请使用 dd_belated dillerdesign.com/experiment/DD_belatedPNG
      • 您甚至可以将掩码字母保存为一张大图像并将其用作精灵。所以每个字母都将是一个 DIV,背景图像移动到正确的位置。如果您想通过不同的字体创建一些蒙版,那将变得更加容易。话虽如此,它并不完美,因为基于图像的字母最终会被等宽。我可能会考虑为此使用 Flash。
      • +1 提供优雅的解决方案,甚至可以走上放置样本的漫长道路 - 太棒了!
      【解决方案7】:

      即使在服务器上,这也不是一个小问题,因为不可能使用颜色掩码直接执行 Fill(),而这正是您所需要的。

      如果字母图像不是白色的,我会更快地遍历现有像素,进行查找并将图案像素写入结果图像:

      Graphics g = Graphics.FromImage(letterImg);
      Brush brush = new System.Drawing.TextureBrush(patternImg);
      for (int x=0;i<letterImg.Width;i++)
        for (int y=0;y<letterImg.Height;y++)
      {
          Color mask = img.GetPixel(x,y);
          //Color pattern = patternImg.GetPixel(x % patternImg.Width, y % patternImg.Height);
          if (mask != Color.White)
      {   
           g.FillRectagle(brush,x,y,1,1);
      }
      
      }
      

      然后在创建后找到一个命名方案将它们缓存在磁盘上,这样你只需要渲染每个模式字母组合一次。

      【讨论】:

        【解决方案8】:

        GDI+ 在 ASP.NET 下运行良好。 (WPF 曾经,但后来被服务包破坏了。不确定它现在是否可以再次工作)。

        在服务器端构建图像非常简单 - 诀窍是将它们链接到客户端请求。我使用了堆栈表示 - 我的文章在这里:

        http://www.hackification.com/2008/10/29/stack-based-processing-part-2/

        【讨论】:

          【解决方案9】:

          在与 OO(海报)确认后,我想加入 Flash。

          Flash 的优势在于它具有非常好的抗锯齿和出色的排版支持(尤其是从 CS4 开始)。您可以选择让整个界面在 Flash 中直接键入带图案的字母,或者只让 swf 根据指定名称和图案的参数呈现结果。

          就我个人而言,我会在 Flash 中制作整个东西,为界面提供可选模式,例如 JSON。但您可以采取的最基本步骤是

          创建一个表单,输入名称和模式选择框

          显示 Flash 文件和参数 patterntype.swf?name=flash&pattern=disco.png

          基本概念是将 Text 设置为模式的掩码。 我在 Flash 中做了一个快速测试,以测试平铺图案的性能(以及它是否真的有效)

          package {
          
              import flash.display.MovieClip;
              import flash.display.Loader;
              import flash.net.URLRequest;
              import flash.events.Event;
              import flash.display.Sprite;
              import flash.display.Bitmap;
              import flash.display.BitmapData;
          
          
              public class PatternType extends MovieClip {
                  /* library element, use the textfield to change the font */
                  public var nameDisplay:NameDisplay;
          
                  private var loader:Loader;
          
                      /* parameters, you can pass these as request parameters, or make a javascript call to get/set them */
                  private var pattern:String = "pattern.png"; 
                  private var nameString:String = "Heidi Klum";
                  private var container:MovieClip;
          
          
                  public function PatternType() {
                      container = new MovieClip();
                      addChild(container);
          
                      nameDisplay = new NameDisplay();
                      nameDisplay.txt.text = nameString;
                      nameDisplay.cacheAsBitmap = true; //mask wont work without this.
                      container.addChild(nameDisplay)
          
                      container.mask = nameDisplay;
          
                      loader = new Loader();
                      loader.contentLoaderInfo.addEventListener(Event.COMPLETE, handlePatternLoaded);
                      loader.load(new URLRequest(pattern));
                  }
          
          
                  private function handlePatternLoaded(e:Event) {
                      trace("complete");
                      var bmp:Bitmap = e.target.content as Bitmap;
          
                      var rows:int = Math.ceil(stage.stageHeight / bmp.height);
                      var cols:int = Math.ceil(stage.stageWidth / bmp.width);
          
                      //tile the texture
                      for(var i:int = 0; i < cols; i++) {
                          for(var j:Number = 0; j < rows; j++) {
                              var b:Bitmap = new Bitmap(bmp.bitmapData.clone());
                              b.x = i * bmp.width;
                              b.y = j * bmp.height;
                              container.addChild(b);
                          }
                      }
                  }
          
              }
          }
          

          当一切都如用户所愿时,您可以从结果中创建一个新的 Bitmap 对象并将数据发送到服务器,服务器可以将数据直接写入位图文件(jpeg 也可以)。

          一些可以让 Flash 卖得更多的东西:

          • 你可以旋转文字
          • 使用异国字体
          • 每个字母使用不同的模式
          • 缩放文本
          • 使用定制的图像过滤器
          • 在 3d 空间中移动(x、y、z 平移旋转、透视)
          • 将结果另存为图像

          【讨论】:

          • Flash 很少是我的首选,但对于这项特殊任务,它可能是最理想的选择。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多