1

コンソール アプリで imageresizer.net を使用して tiff 画像からページを取得していますが、tiff にさまざまな画像タイプのページが含まれている場合、imageresizer が抽出したものが常に元のページを表しているとは限りません。

このコードでマネージ API を使用しています。 ImageBuilder.Current.Build(sourceImagePath, destinationImagePath, new ResizeSettings("page=[whatever]"));

TIFF 画像には次のものが含まれています...

  • ページ 1、画像タイプ「バイレベル (白はゼロ)」、圧縮「グループ 3」、サイズ「485kb」。
  • 2ページ目、画像タイプ「YCbCr(2,1サブサンプリング)」、圧縮「JPEG(旧形式)」、サイズ「11MB」。
  • 3ページ、画像タイプ「YCbCr(2,1サブサンプリング)」、圧縮「JPEG(旧形式)」、サイズ「11MB」。
  • 4ページ、画像タイプ「グレースケール(256グレー、黒ゼロ)」、圧縮「JPEG(旧スタイル)」、サイズ「4MB」。

私が得ている動作は...

  • ページ 1 の抽出は正しく機能します。
  • ページ 2 を抽出すると、ページ 1 の画像が抽出されます。
  • ページ 3 を抽出すると、ページ 1 の画像が抽出されますが、画像の左側で約 1 cm 幅の帯に押しつぶされ、残りの画像は黒くなっています。
  • ページ 4 の抽出は正しく機能します。

また、 libtiff.net を使用して、このメソッドを使用して同じ画像を抽出しましたが、同じ障害は発生しません。

編集 - このコードを使用して、Wic デコーダーでテストします。

var settings = new ResizeSettings("decoder=wic&page=" + pageNumber);
Config.Current.Plugins.GetOrInstall<WicDecoderPlugin>();
ImageBuilder.Current.Build(sourceImagePath, destImagePath, settings);

これはページ 1 と 4 で機能しますが (変更はありません)、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」というメッセージが表示されます。Wic デコーダー使用時のページ 2 & 3 のエラー。

編集 2 - 失敗しているビットを MVC プロジェクトに変換して、/resizer.debug を取得します。

Image resizer diagnostic sheet      29/06/2012 4:08:14 a.m.

4 Issues detected:

(Warning):  To potentially see additional errors here, perform an image resize request.


(Warning):  You are running a hotfix version of the ImageResizer.
            You should upgrade to a released version with an equal or higher version number as soon as possible. Hotfix and release DLLs with the same version number are not the same - the release DLL should be used instead.
            Assemblies marked as hotfix versions: ImageResizer, ImageResizer.Mvc

(Warning):  NoCache is only for development usage, and cannot scale to production use.
            Add DiskCache or CloudFront for production use

(Warning):  Potentially incompatible ImageResizer assemblies were detected.
            Please make sure all ImageResizer assemblies are from the same version. Compatibility issues are possible if you mix plugins from different releases.
            3.2.3 assemblies: ImageResizer, ImageResizer.Mvc
            3.2.2 assemblies: ImageResizer.Plugins.Logging, ImageResizer.Plugins.Wic


You are using paid bundles: Design Bundle

Registered plugins:

ImageResizer.Plugins.Basic.DefaultEncoder
ImageResizer.Plugins.Basic.NoCache
ImageResizer.Plugins.Basic.ClientCache
ImageResizer.Plugins.Basic.Diagnostic
ImageResizer.Plugins.Basic.SizeLimiting
ImageResizer.Plugins.MvcRoutingShim.MvcRoutingShimPlugin
ImageResizer.Plugins.WicDecoder.WicDecoderPlugin
ImageResizer.Plugins.Logging.LoggingPlugin

Configuration:

<resizer>
<plugins>
<add name="MvcRoutingShim" />
<add name="WicDecoder" />
<add name="Logging" />
</plugins>
</resizer>


Accepted querystring keys:

quality, format, thumbnail, maxwidth, maxheight, width, height, w, h, scale, stretch, crop, cropxunits, cropyunits, page, bgcolor, rotate, flip, sourceFlip, sFlip, sRotate, borderWidth, borderColor, paddingWidth, paddingColor, ignoreicc, frame, useresizingpipeline, cache, process, margin, anchor, dpi, mode, zoom, 

Accepted file extensions:

bmp, gif, exif, png, tif, tiff, tff, jpg, jpeg, jpe, jif, jfif, jfi, 

Environment information:

Running Microsoft Windows NT 6.1.7601 Service Pack 1 and CLR 4.0.30319.269
Trust level: Unrestricted
OS bitness: x86 !! Warning, running as 32-bit on a 64-bit OS(AMD64). This will limit ram usage !!
Executing assembly: C:\Program Files (x86)\Common Files\Microsoft Shared\DevServer\10.0\WebDev.WebServer40.exe
IntegratedPipeline: False

Loaded assemblies:

mscorlib                                 Assembly: 4.0.0.0         File: 4.0.30319.269   Info: 4.0.30319.269
System.Web                               Assembly: 4.0.0.0         File: 4.0.30319.272   Info: 4.0.30319.272
System                                   Assembly: 4.0.0.0         File: 4.0.30319.269   Info: 4.0.30319.269
System.Core                              Assembly: 4.0.0.0         File: 4.0.30319.233   Info: 4.0.30319.233
System.Configuration                     Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Xml                               Assembly: 4.0.0.0         File: 4.0.30319.233   Info: 4.0.30319.233
System.Runtime.Caching                   Assembly: 4.0.0.0         File: 4.0.30319.237   Info: 4.0.30319.237
Microsoft.Build.Utilities.v4.0           Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Web.RegularExpressions            Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
Microsoft.Build.Framework                Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Data                              Assembly: 4.0.0.0         File: 4.0.30319.237   Info: 4.0.30319.237
Microsoft.JScript                        Assembly: 10.0.0.0        File: 10.0.30319.1    Info: 10.0.30319.1
CppCodeProvider                          Assembly: 10.0.0.0        File: 10.0.30319.1    Info: 10.0.30319.1
System.Web.WebPages.Deployment           Assembly: 1.0.0.0         File: 1.0.20105.407  
System.Web.WebPages                      Assembly: 1.0.0.0         File: 1.0.20105.407  
System.Web.Mvc                           Assembly: 3.0.0.0         File: 3.0.20105.0    
Microsoft.Web.Infrastructure             Assembly: 1.0.0.0         File: 1.0.20105.407  
System.Web.WebPages.Razor                Assembly: 1.0.0.0         File: 1.0.20105.407  
System.Web.Razor                         Assembly: 1.0.0.0         File: 1.0.20105.407  
App_global.asax.ijrgfwnu                 Assembly: 0.0.0.0        
PNCC.LimDocumentBuilder.ImageResizerTest Assembly: 1.0.0.0         File: 1.0.0.0        
WebDev.WebHost40                         Assembly: 10.0.0.0        File: 10.0.40219.1    Info: 10.0.40219.1
System.Web.Mobile                        Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.ServiceModel.Activation           Assembly: 4.0.0.0         File: 4.0.30319.233   Info: 4.0.30319.233
System.ServiceModel                      Assembly: 4.0.0.0         File: 4.0.30319.233   Info: 4.0.30319.233
System.Runtime.DurableInstancing         Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
SMDiagnostics                            Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Xaml.Hosting                      Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Web.Extensions                    Assembly: 4.0.0.0         File: 4.0.30319.272   Info: 4.0.30319.272
Microsoft.CSharp                         Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Web.Services                      Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Drawing                           Assembly: 4.0.0.0         File: 4.0.30319.282   Info: 4.0.30319.282
System.EnterpriseServices                Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.IdentityModel                     Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Runtime.Serialization             Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.ServiceModel.Web                  Assembly: 4.0.0.0         File: 4.0.30319.233   Info: 4.0.30319.233
System.Activities                        Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.ServiceModel.Activities           Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.WorkflowServices                  Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Data.DataSetExtensions            Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Xml.Linq                          Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.ComponentModel.DataAnnotations    Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Web.DynamicData                   Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Web.ApplicationServices           Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
EntityFramework                          Assembly: 4.1.0.0         File: 4.1.10331.0     Info: 4.1.10331.0
ImageResizer                             Assembly: 3.2.3.766       File: 3.2.3.766       Info: 3-2-beta-3-temp-hotfix-jun-27-2012-9am  Commit: a0f4f1e
ImageResizer.Mvc                         Assembly: 3.2.3.766       File: 3.2.3.766       Info: 3-2-beta-3-temp-hotfix-jun-27-2012-9am  Commit: a0f4f1e
ImageResizer.Plugins.Logging             Assembly: 3.2.2.0         File: 3.2.2.0         Info: 3-2-beta-2  Commit: 3704dd6
ImageResizer.Plugins.Wic                 Assembly: 3.2.2.0         File: 3.2.2.0         Info: 3-2-beta-2  Commit: 3704dd6
NLog                                     Assembly: 2.0.0.0        
System.Web.Abstractions                  Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
System.Web.Helpers                       Assembly: 1.0.0.0         File: 1.0.20105.407  
System.Web.Routing                       Assembly: 4.0.0.0         File: 4.0.30319.1     Info: 4.0.30319.1
4

2 に答える 2

1

ここでは、BuilderExtension をサブクラス化し、DecodeStream をオーバーライドして、libtiff.net に接着しようとしています。

これは、サイズの異なるページと色空間が異なるページの 2 つのテスト tiffです。ImageBuilder v3.2.2 に対してコンパイルしました。

次のコードで ImageResizer v3.2.2 ソースの ConsoleApplication プロジェクトを使用すると、エラーが発生します。現時点ではこの問題を修正する時間がなくなったので、他の誰かがこれをさらに進めたい場合に備えて、ここに進捗状況を載せると思いました.

私のテストコード

パラメータが無効なImageResizer.ImageBuilder.PrepareDestinationBitmap()オンラインs.destBitmap = ...で失敗していると思います。エラー。寸法は w=9994,h=7102 であり、これはメモリの問題である可能性があると思われますが、最初に使用して tiff をデコードし、それを ImageResizer にメモリ ストリームとして渡すと、エラーは発生しません。また、この障害は v3.2.2 と v3.2.3 の両方で発生します。DecodeTiffTo32BitBitmap()

var Path = @"[whatever]\TiffDecoderTests\";
var c = new Config();      
new TiffDecoder().Install(c);      
c.BuildImage(Path + "different_page_sizes.TIF", Path + "different_page_sizes-page2-TiffReader.png", "format=png&page=2&decoder=tiffdecoder");   

私の TiffDecoder クラス:

namespace ImageResizer.Plugins.TiffDecoder
{
  using System;
  using System.Collections.Generic;
  using System.Drawing;
  using System.Drawing.Imaging;
  using System.Globalization;
  using System.IO;
  using System.Linq;

  using BitMiracle.LibTiff.Classic;

  using ImageResizer;
  using ImageResizer.Configuration;
  using ImageResizer.Resizing;

  public class TiffDecoder : BuilderExtension, IPlugin, IFileExtensionPlugin
  {
    private static readonly string[] supportedExtensions = new[] { ".tiff", ".tif", ".tff" };

    public IPlugin Install(Config c)
    {
      c.Plugins.add_plugin(this);
      return this;
    }

    public bool Uninstall(Config c)
    {
      c.Plugins.remove_plugin(this);
      return true;
    }

    public IEnumerable<string> GetSupportedFileExtensions()
    {
      return supportedExtensions;
    }

    public override Bitmap DecodeStream(Stream s, ResizeSettings settings, string optionalPath)
    {
      var requested = "tiffdecoder".Equals(settings["decoder"], StringComparison.OrdinalIgnoreCase);
      if (!string.IsNullOrEmpty(settings["decoder"]) && !requested)
      {
        return null; // Don't take it away from the requested decoder
      }

      // If a tiff is coming in, try first, before Bitmap tries to parse it.      
      if (requested || (optionalPath != null && supportedExtensions.Any(ext => optionalPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))))
      {
        return this.Decode(s, settings);
      }

      return null;
    }

    public override Bitmap DecodeStreamFailed(Stream s, ResizeSettings settings, string optionalPath)
    {
      // Catch tiff files not ending in an expected extension
      try
      {
        return this.Decode(s, settings);
      }
      catch
      {
        return null;
      }
    }

    public Bitmap Decode(Stream s, ResizeSettings settings)
    {
      return DecodeTiffTo32BitBitmap(s, settings["page"]);
    }

    private static Bitmap DecodeTiffTo32BitBitmap(Stream s, string page)
    {
      s.Position = 0;
      using (var image = Tiff.ClientOpen(string.Empty, "r", s, new TiffStream()))
      {
        SetDirectory(image, page);

        // Find the width and height of the image
        var value = image.GetField(TiffTag.IMAGEWIDTH);
        var width = value[0].ToInt();

        value = image.GetField(TiffTag.IMAGELENGTH);
        var height = value[0].ToInt();

        // Read the image into the memory buffer
        var raster = new int[height * width];
        if (!image.ReadRGBAImage(width, height, raster))
        {
          return null;
        }

        // Caller needs to handle disposing the bitmap.
        var bmp = new Bitmap(width, height, PixelFormat.Format32bppRgb);
        var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

        var bmpdata = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
        var bits = new byte[bmpdata.Stride * bmpdata.Height];

        for (var y = 0; y < bmp.Height; y++)
        {
          var rasterOffset = y * bmp.Width;
          var bitsOffset = (bmp.Height - y - 1) * bmpdata.Stride;

          for (var x = 0; x < bmp.Width; x++)
          {
            var rgba = raster[rasterOffset++];
            bits[bitsOffset++] = (byte)((rgba >> 16) & 0xff);
            bits[bitsOffset++] = (byte)((rgba >> 8) & 0xff);
            bits[bitsOffset++] = (byte)(rgba & 0xff);
            bits[bitsOffset++] = (byte)((rgba >> 24) & 0xff);
          }
        }

        System.Runtime.InteropServices.Marshal.Copy(bits, 0, bmpdata.Scan0, bits.Length);
        bmp.UnlockBits(bmpdata);

        return bmp;
      }
    }

    /// <summary>
    /// Sets the TIFF directory to the first that matches the requested page number, otherwise:
    /// - If page not set OR less than 0, use the first page in the TIFF.
    /// - If tiff has no directories with the "PAGE" tag, use the first frame in the TIFF.
    /// </summary>
    /// <param name="image">The image.</param>
    /// <param name="page">The page.</param>
    /// <remarks>
    /// From what I can tell a TIFF image can store any pages in any directory, so the 1st dir 
    /// might not hold the 1st page - this is why we first iterate all frames looking for a PAGE tag.
    /// </remarks>    
    private static void SetDirectory(Tiff image, string page)
    {
      var pageIndex = GetAdjustedPage(page);
      var numberOfDirectories = image.NumberOfDirectories();

      for (short dirNumber = 0; dirNumber < numberOfDirectories; ++dirNumber)
      {
        image.SetDirectory(dirNumber);

        // Ignore pages that might be thumbnails
        var subFileType = image.GetField(TiffTag.SUBFILETYPE);
        if (subFileType == null || subFileType[0].ToString().ToUpper() != "PAGE")
        {
          continue;
        }

        // Stop if page found
        if (pageIndex == int.Parse(image.GetField(TiffTag.PAGENUMBER)[0].ToString()))
        {
          return;
        }
      }

      // Default to the first frame if the page wasn't found.
      image.SetDirectory(0);
    }

    private static int GetAdjustedPage(string page)
    {
      var pageIndex = 1;
      if (!string.IsNullOrEmpty(page))
      {
        int.TryParse(page, NumberStyles.Number, NumberFormatInfo.InvariantInfo, out pageIndex);
      }

      // So users can use 1-based numbers
      return Math.Max(1, pageIndex) - 1;
    }
  }
}
于 2012-07-03T23:20:48.870 に答える
0

2012 年 12 月 12 日更新:

FreeImageDecoder プラグインが複数ページの TIFF ファイルをサポートし、libtiff を内部で使用するようになりました。これは、非常に複雑な/まれな .TIFF ファイルを処理するための推奨される方法です。


TIFF 形式は非常に複雑で、標準化が不十分です。ほとんどのライブラリ (GDI+ (System.Drawing) や WIC (WPF) など) は、標準の一部しか実装しておらず、事実上の機能や追加機能は言うまでもありません。

このレベルの .TIFF サポートを取得するには、libtifflibtiff.netなどの .TIFF サポート専用のライブラリを使用する必要があります。

ImageResizer、FreeImage および FreeImageDecoder プラグインを介して LibTiff と統合されていますが、マルチページ サポートはまだ実装されていません

パドルなしで小川を上ることはできません。ジレンマを解決する方法はたくさんあります。

  1. FreeImageDecoderをフォークし、複数ページのサポートを追加します。難易度: 7
  2. BuilderExtension をサブクラス化し、 DecodeStreamをオーバーライドして、 libtiff.netに接着します。難易度: 5
  3. BuilderExtension をサブクラス化し、DecodeStream をオーバーライドして、libtiff に接着します。難易度:10
  4. UserVoice サイトにアイデアを投稿して、30 票を獲得してください。困難:?
  5. それをするために私にお金を払ってください。難易度: 3 (ただし、次に利用できるスロットは今から数か月後です)。

ImageBuilder.DecodeStream、PsdReader、WicDecoder、FreeImageDeocoder、および PdfRenderer の 4 つのデコーダの実装例が既にあります。それらのソース コードは、ダウンロードに含まれています。平均的なデコーダーに必要なコードは 80 行未満です。

于 2012-06-30T15:35:52.497 に答える