Search code examples
objective-cimagensmenuitemmacos-big-sur

NSMenuItem image is distorted when drawn


I'm building up a list of submenu items, that contain an image. I do load an image from the bundle, then want to draw it in the menu item swatch.

Here's the code:

  NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"Title" action:nil keyEquivalent:@""];

  [item setAction:@selector(action:)];
  [item setTarget:self];
  [item setEnabled:YES];

  NSImage *img = [[NSImage alloc] initWithSize:NSMakeSize(24, 16)];

  [img lockFocus];

  NSString *imgFile = [mainBundle pathForResource:@"swatch" ofType: @"png"];
  NSImage *swtch = [[NSImage alloc] initWithContentsOfFile:imgFile];

  NSRect imgRect;
  imgRect.origin = NSZeroPoint;
  imgRect.size = [swtch size];
  [swtch drawInRect:NSMakeRect(0, 0, 24, 16)
           fromRect:imgRect
          operation:NSCompositingOperationSourceOver
           fraction:1.0f];

  [img unlockFocus];

  [item setImage:[img copy]];

If I select the menu item from the submenu, the NSPopupButton displays the correct image.

popup button

If I get a bitmap representation from "img", it is correct, a downsized copy of "swtch".

But the menu item looks wrong:

menu item image

It only started this on Big Sur, prevoiusly all looked good. Do I need to setup menu item or its cell different?


Solution

  • It looks like the problem is in the image itself. It probably has an alpha channel, but the antialiasing around the text edges was composited on a white background (hard to explain, but it can and does happen depending on how the image was made.)

    Does this image always draw on a white background? If so, try re-saving the .png file without transparency. You can do this in Preview.app. File->Export, uncheck Alpha.

    If you need black antialiased text that composites properly atop any colored background, you'd need to redo the image so there's no white in it. This can be done in Photoshop.

    (You might also be able to fix it by changing the blend mode to something like NSCompositingOperationDarken or NSCompositingOperationPlusDarker, but it would be cleaner to repair the image file.)