在MonoMac中使用压缩保存JPG

时间:2012-10-28 14:06:12

标签: compression jpeg monomac

这是我使用压缩保存JPG的MonoMac代码。这很简单,只需设置NSImageCompressionFactor即可。羞耻它不起作用。

public void SaveImage(NSImage MyNSImage,string Location, float Quality) 
{
    NSBitmapImageRep BRep=(NSBitmapImageRep)MyNSImage.Representations()[0]; 
    NSDictionary Dic= NSDictionary.FromObjectAndKey(new NSNumber(Quality),new NSString("NSImageCompressionFactor")); 
    NSData D=BRep.RepresentationUsingTypeProperties(NSBitmapImageFileType.Jpeg,Dic); 
    System.IO.Stream S=D.AsStream(); 
    SaveStream(Location,S); 
    S.Dispose(); 
    D.Dispose(); 
} 

//This save function works fine so ignore it.
void SaveStream(string FileName, Stream Source) 
{ 
    FileStream FS=File.OpenWrite(FileName); 
    int Read=0; 
    byte[] Buffer=new byte[1024]; 
    Source.Seek(0, SeekOrigin.Begin); 
    do{ 
        Read = Source.Read(Buffer, 0, 1024); 
        FS.Write(Buffer, 0, Read); 
    }while(Read>0); 
    FS.Close(); 
} 

它总是保存为100%,但我做错了什么?希望有些聪明的人知道答案。

3 个答案:

答案 0 :(得分:0)

有一个包含所有这些属性字典的通用设计模式:它们的键是字符串常量(具有该名称的变量),而不是字符串,而Objective C运行时按地址匹配它们,而不是按值匹配。< / p>

例如,在您的情况下,NSImageCompressionFactor被声明为

NSString *NSImageCompressionFactor;

在Objective C中它被初始化为一些常量字符串(理论上可能是任何东西),它基本上是指向某个不透明值的指针。

在Objective C中填充属性字典时,您使用变量的名称(即您只需编写NSImageCompressionFactor)而不是创建新的字符串实例(@"NSImageCompressionFactor")。

在MonoMac中,我们为这些字典键创建字符串属性,例如参见MonoMac.Foundation.NSUrl.ContentAccessDateKey

但是,它们在一些地方丢失了(您的位图图像属性就是其中之一,我只是将它们添加到monomac commit 115f1eb中的NSBitmapImageRep)。如果以后有人发现更多丢失的属性,请只需在bugzilla.xamarin.com提交错误报告。

如果您使用的是旧版MonoMac,还有一种解决方法。在生成器输入文件(monomac/src/appkit.cs)中,这些声明如下:

[Field ("NSImageCompressionMethod")]
NSString CompressionMethod { get; }

[Field ("NSImageCompressionFactor")]
NSString CompressionFactor { get; }

然后发电机发出:

[CompilerGenerated]
static readonly IntPtr AppKit_libraryHandle = Dlfcn.dlopen (Constants.AppKitLibrary, 0);
[CompilerGenerated]
static NSString _CompressionMethod;
public static NSString CompressionMethod {
    get {
        if (_CompressionMethod == null)
            _CompressionMethod = Dlfcn.GetStringConstant (AppKit_libraryHandle, "NSImageCompressionMethod");
        return _CompressionMethod;
    }
}
[CompilerGenerated]
static NSString _CompressionFactor;
public static NSString CompressionFactor {
    get {
        if (_CompressionFactor == null)
            _CompressionFactor = Dlfcn.GetStringConstant (AppKit_libraryHandle, "NSImageCompressionFactor");
        return _CompressionFactor;
    }
}

您可以在应用中的某处执行相同操作。

<强>更新

让我们首先看一下Objective C中的示例(完整示例here,图片来自Wikipedia):

- (NSData *)saveImage:(NSImage *)image location:(NSString *)location quality:(float)quality {
    NSBitmapImageRep *imageRep = [[image representations] objectAtIndex:0];
    NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithFloat:quality], NSImageCompressionFactor, nil];

    NSData *data = [imageRep representationUsingType:NSJPEGFileType properties:dict];
    printf("DATA: %ld\n", [data length]);
    return data;
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSString *path = [[NSBundle mainBundle] bundlePath];
    NSString *resDir = [[path stringByAppendingPathComponent:@"Contents"] stringByAppendingPathComponent:@"Resources"];
    NSString *filePath = [resDir stringByAppendingPathComponent:@"Neptune.jpg"];

    NSImage *image = [[NSImage alloc] initWithContentsOfFile:filePath];

    [self saveImage:image location:@"output.jpg" quality:0.0];
    [self saveImage:image location:@"output.jpg" quality:0.25];
    [self saveImage:image location:@"output.jpg" quality:0.5];
    [self saveImage:image location:@"output.jpg" quality:1.0];
}

现在让我们把它变成一个MonoMac应用程序(完整样本here):

public override void FinishedLaunching (NSObject notification)
{
    mainWindowController = new MainWindowController ();
    mainWindowController.Window.MakeKeyAndOrderFront (this);

    var path = Path.Combine (NSBundle.MainBundle.BundlePath, "Contents", "Resources");
    var filePath = Path.Combine (path, "Neptune.jpg");

    var image = new NSImage (filePath);
    Console.WriteLine (image);

    SaveImage (image, "output.jpg", 0.0f);
    SaveImage (image, "output.jpg", 0.25f);
    SaveImage (image, "output.jpg", 0.5f);
    SaveImage (image, "output.jpg", 1.0f);
}

public void SaveImage (NSImage image, string location, float quality) 
{
    var brep = (NSBitmapImageRep)image.Representations ()[0];

    var dict = NSDictionary.FromObjectAndKey (NSNumber.FromFloat (quality), NSBitmapImageRep.CompressionFactor);

    var data = brep.RepresentationUsingTypeProperties (NSBitmapImageFileType.Jpeg, dict);
    Console.WriteLine (data.Length);
}

这会打印与Objective C样本相同的大小,因此这实际上有效。

答案 1 :(得分:0)

好的,我越来越接近,但它仍然保存在100%,还有更多的建议吗?:

public void SaveImage(NSImage MyNSImage,string Location, float Quality) 
{

            NSBitmapImageRep BRep=(NSBitmapImageRep)MyNSImage.Representations()[0];
            NSDictionary Dic= NSDictionary.FromObjectAndKey(new NSNumber(Quality),NSImageCompressionFactor);
            NSData D=BRep.RepresentationUsingTypeProperties(NSBitmapImageFileType.Jpeg,Dic);
            System.IO.Stream S=D.AsStream();
            SaveStream(Location,S);
            S.Dispose();
            D.Dispose();

    }
    static readonly IntPtr AppKit_libraryHandle = MonoMac.ObjCRuntime.Dlfcn.dlopen (MonoMac.Constants.AppKitLibrary, 0);

    static NSString _NSImageCompressionFactor;
    public static NSString NSImageCompressionFactor {
        get {
            if (_NSImageCompressionFactor == null) {
                _NSImageCompressionFactor= MonoMac.ObjCRuntime.Dlfcn.GetStringConstant (AppKit_libraryHandle, "NSImageCompressionFactor");
            }
            return _NSImageCompressionFactor;
        }
    }

答案 2 :(得分:0)

我最终放弃了尝试让它按上述方式工作。

我找到了这个C#jpeg编码器。

http://www.codeproject.com/Articles/83225/A-Simple-JPEG-Encoder-in-C

您需要更正评论中指定的一行。