1

这是我用于保存带压缩的 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%,我做错了什么?希望有聪明人知道答案。

4

3 回答 3

0

所有这些属性字典都有一个通用的设计模式:它们的键是字符串常量(具有该名称的变量),而不是字符串,并且 Objective C 运行时通过地址而不是值来匹配它们。

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

NSString *NSImageCompressionFactor;

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

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

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

但是,它们在一些地方丢失了(您的位图图像属性就是其中之一,我只是将它们添加到NSBitmapImageRepmonomac commit 115f1eb 中)。如果将来有人发现更多缺失的属性,请简单地在 中提交错误报告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 中的一个示例开始(此处为完整示例,图片来自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 应用程序(完整示例在这里):

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 示例相同的大小,因此这确实有效。

于 2012-10-29T14:26:55.557 回答
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;
        }
    }
于 2012-11-14T19:53:19.237 回答
0

我最终放弃了尝试让它像上面那样工作。

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

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

您需要更正注释中指定的一行。

于 2012-11-28T16:18:58.133 回答