Skip to content

Commit

Permalink
modernize NSImage usage
Browse files Browse the repository at this point in the history
- Fixes up NSImage to use a technique that doesn't depend on the
  DPI of the current screen and just uses pixels
- Fixes a crash when releasing the image; the crash was caused by
  a `memset` call getting a different size for the filename buffer.
  I solved this by passing the size down, which is safer than just
  assuming anyway.  I added an ASAN cmake option to make it easier
  to turn up the debugging and understand where the memory corruption
  had come from.

refs: #14
  • Loading branch information
wez committed Jan 15, 2021
1 parent 5501843 commit 1dbe1be
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 31 deletions.
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()

option(ASAN "whether to enable ASAN" OFF)

find_program(GIT git)
if(GIT)
execute_process(
Expand Down Expand Up @@ -92,3 +94,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
"-framework IOKit"
)
endif()

if (ASAN)
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
endif()
3 changes: 2 additions & 1 deletion src/AtomicParsley.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,8 @@ void APar_SupplySelectiveTypeCreatorCodes(const char *inputPath,

bool ResizeGivenImage(const char *filePath,
PicPrefs myPicPrefs,
char *resized_path);
char *resized_path,
size_t resized_path_len);

char *GenreIntToString(int genre);
uint8_t StringGenreToInt(const char *genre_string);
Expand Down
77 changes: 49 additions & 28 deletions src/nsimage.mm
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ static void DetermineType(const char *picfilePath, bool &isJPEG, bool &isPNG) {
}
}

static char *
DeriveNewPath(const char *filePath, PicPrefs myPicPrefs, char *newpath) {
static char *DeriveNewPath(const char *filePath,
PicPrefs myPicPrefs,
char *newpath,
size_t newpath_len) {
const char *suffix = strrchr(filePath, '.');

size_t filepath_len = strlen(filePath);
memset(newpath, 0, MAXPATHLEN + 1);
memset(newpath, 0, newpath_len);
size_t base_len = filepath_len - strlen(suffix);
memcpy(newpath, filePath, base_len);
memcpy(newpath + base_len, "-resized-", 9);
Expand All @@ -74,11 +76,44 @@ static void DetermineType(const char *picfilePath, bool &isJPEG, bool &isPNG) {
return newpath;
}

static NSImage *DoResize(NSImage *sourceImage, NSSize newSize) {
if (!sourceImage.isValid) {
return nil;
}

NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:newSize.width
pixelsHigh:newSize.height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bytesPerRow:0
bitsPerPixel:0];
rep.size = newSize;

[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext
setCurrentContext:[NSGraphicsContext
graphicsContextWithBitmapImageRep:rep]];
[sourceImage drawInRect:NSMakeRect(0, 0, newSize.width, newSize.height)
fromRect:NSZeroRect
operation:NSCompositingOperationCopy
fraction:1.0];
[NSGraphicsContext restoreGraphicsState];

NSImage *newImage = [[NSImage alloc] initWithSize:newSize];
[newImage addRepresentation:rep];
return newImage;
}

bool ResizeGivenImage(const char *filePath,
PicPrefs myPicPrefs,
char *resized_path) {
char *resized_path,
size_t resized_path_len) {
bool resize = false;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSImage *source = [[NSImage alloc]
initWithContentsOfFile:[NSString stringWithUTF8String:filePath]];
Expand Down Expand Up @@ -179,37 +214,23 @@ bool ResizeGivenImage(const char *filePath,
NSSize size = NSMakeSize(hmax, vmax);

if (resize) {
[NSApplication sharedApplication];
[[NSGraphicsContext currentContext]
setImageInterpolation:NSImageInterpolationHigh];

[source setSize:size];
NSImage *image = DoResize(source, size);

NSImage *image = [[NSImage alloc] initWithSize:size];
[image lockFocus];
NSData *imageData = [image TIFFRepresentation];
NSBitmapImageRep *bitmap = [NSBitmapImageRep imageRepWithData:imageData];

NSEraseRect(destinationRect);
[source drawInRect:destinationRect
fromRect:destinationRect
operation:NSCompositingOperationCopy
fraction:1.0];

NSBitmapImageRep *bitmap =
[[NSBitmapImageRep alloc] initWithFocusedViewRect:destinationRect];
NSBitmapImageFileType filetype;
NSDictionary *props;

if ((isPNG && !myPicPrefs.allJPEG) || myPicPrefs.allPNG) {
filetype = NSBitmapImageFileTypePNG;
props = nil;

} else {
filetype = NSBitmapImageFileTypeJPEG;
props = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.7]
forKey:NSImageCompressionFactor];
}
NSData *data = [bitmap representationUsingType:filetype properties:props];

unsigned dataLength = [data length]; // holds the file length

int iter = 0;
Expand All @@ -227,21 +248,21 @@ bool ResizeGivenImage(const char *filePath,
}
}

[bitmap release];
NSString *outFile = [NSString
stringWithUTF8String:DeriveNewPath(filePath, myPicPrefs, resized_path)];
// NSLog(outFile);
NSString *outFile =
[NSString stringWithUTF8String:DeriveNewPath(filePath,
myPicPrefs,
resized_path,
resized_path_len)];
[[NSFileManager defaultManager] createFileAtPath:outFile
contents:data
attributes:nil];

[image unlockFocus];
[image release];
[bitmap release];
memcpy(resized_path,
[outFile cStringUsingEncoding:NSUTF8StringEncoding],
[outFile lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
}
[source release];
[pool release];
return resize;
}
8 changes: 6 additions & 2 deletions src/parsley.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2938,9 +2938,13 @@ void APar_MetaData_atomArtwork_Set(const char *artworkPath,
// any way
myPicturePrefs = APar_ExtractPicPrefs(env_PicOptions);

char *resized_filepath = (char *)calloc(1, sizeof(char) * MAXPATHLEN + 1);
size_t resized_filepath_len = MAXPATHLEN + 1;
char *resized_filepath = (char *)calloc(1, resized_filepath_len);

if (ResizeGivenImage(artworkPath, myPicturePrefs, resized_filepath)) {
if (ResizeGivenImage(artworkPath,
myPicturePrefs,
resized_filepath,
resized_filepath_len)) {
APar_MetaData_atomArtwork_Init(desiredAtom->AtomicNumber,
resized_filepath);

Expand Down

0 comments on commit 1dbe1be

Please sign in to comment.