forked from spacetelescope/toasty
-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fits thumbnails #91
Open
imbasimba
wants to merge
5
commits into
WorldWideTelescope:master
Choose a base branch
from
imbasimba:fits-thumbnails
base: master
Could not load branches
Branch not found: {{ refName }}
Could not load tags
Nothing to show
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Fits thumbnails #91
Changes from 2 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
eb45b5b
Enabled thumbnail creation for FITS files
imbasimba 1d72cfd
Corrected spelling
imbasimba 21e5275
Extracted the coercion of data into PIL format from aspil. Also let t…
imbasimba 0b93144
Fixed typo
imbasimba 0284e8e
Fixed incorrect row breaks
imbasimba File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -228,18 +228,6 @@ def make_maskable_buffer(self, buf_height, buf_width): | |
|
||
return Image.from_array(arr) | ||
|
||
def try_as_pil(self): | ||
""" | ||
Attempt to convert this mode into a PIL image mode string. | ||
|
||
Returns | ||
------- | ||
A PIL image mode string, or None if there is no exact counterpart. | ||
""" | ||
if self == ImageMode.F16x3: | ||
return None | ||
return self.value | ||
|
||
|
||
def _wcs_to_parity_sign(wcs): | ||
h = wcs.to_header() | ||
|
@@ -854,24 +842,44 @@ def asarray(self): | |
self._array = np.asarray(self._pil) | ||
return self._array | ||
|
||
def aspil(self): | ||
def aspil(self, pixel_cut_low=None, pixel_cut_high=None): | ||
imbasimba marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"""Obtain the image data as :class:`PIL.Image.Image`. | ||
|
||
Parameters | ||
---------- | ||
pixel_cut_low : number or ``None`` (the default) | ||
An optional value used to stretch the pixel values to the new range | ||
as defined by pixel_cut_low and pixel_cut_high. Only used if the | ||
image was not loaded as a PIL image, and must be used together with | ||
pixel_cut_high. To get reasonable values for arrays with dtype other | ||
than ``unit8`` this parameter is highly recommended. | ||
pixel_cut_high : number or ``None`` (the default) | ||
An optional value used to stretch the pixel values to the new range | ||
as defined by pixel_cut_low and pixel_cut_high. Only used if the | ||
image was not loaded as a PIL image, and must be used together with | ||
pixel_cut_low. To get reasonable values for arrays with dtype other | ||
than ``unit8`` this parameter is highly recommended. | ||
Returns | ||
------- | ||
If the image was loaded as a PIL image, the underlying object will be | ||
returned. Otherwise the data array will be converted into a PIL image, | ||
which requires that the array have an RGB(A) format with a shape of | ||
``(height, width, planes)``, where ``planes`` is 3 or 4, and a dtype of | ||
``uint8``. | ||
``(height, width, planes)``, where ``planes`` is 3 or 4. | ||
|
||
""" | ||
if self._pil is not None: | ||
return self._pil | ||
if self.mode.try_as_pil() is None: | ||
raise Exception( | ||
f"Toasty image with mode {self.mode} cannot be converted to PIL" | ||
) | ||
if ( | ||
pixel_cut_low is not None | ||
and pixel_cut_high is not None | ||
and pixel_cut_low != pixel_cut_high | ||
): | ||
# TODO don't operate on potential alpha channel | ||
array = (self._array - pixel_cut_low) / ( | ||
pixel_cut_high - pixel_cut_low | ||
) * 255 + 0.5 | ||
array = np.uint8(np.clip(array, 0, 255)) | ||
imbasimba marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return pil_image.fromarray(array) | ||
return pil_image.fromarray(self._array) | ||
|
||
@property | ||
|
@@ -1167,9 +1175,7 @@ def is_completely_masked(self): | |
elif self.mode == ImageMode.RGBA: | ||
return np.all(i[..., 3] == 0) | ||
else: | ||
raise Exception( | ||
f"unhandled mode `{self.mode}` in is_completely_masked" | ||
) | ||
raise Exception(f"unhandled mode `{self.mode}` in is_completely_masked") | ||
|
||
def save( | ||
self, path_or_stream, format=None, mode=None, min_value=None, max_value=None | ||
|
@@ -1205,7 +1211,7 @@ def save( | |
if format in PIL_RGB_FORMATS and mode is None: | ||
mode = ImageMode.RGB | ||
if mode is not None: | ||
pil_image = pil_image.convert(mode.try_as_pil()) | ||
pil_image = pil_image.convert(mode.value) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a little wary of dropping the check here since there are ImageMode values that are not valid inputs to |
||
pil_image.save(path_or_stream, format=PIL_FORMATS[format]) | ||
elif format == "npy": | ||
np.save(path_or_stream, self.asarray()) | ||
|
@@ -1239,26 +1245,31 @@ def save( | |
overwrite=True, | ||
) | ||
|
||
def make_thumbnail_bitmap(self): | ||
def make_thumbnail_bitmap(self, pixel_cut_low=None, pixel_cut_high=None): | ||
"""Create a thumbnail bitmap from the image. | ||
|
||
Parameters | ||
---------- | ||
pixel_cut_low : number or ``None`` (the default) | ||
An optional value used to stretch the pixel values to the new range | ||
as defined by pixel_cut_low and pixel_cut_high. Only used if the | ||
image was not loaded as a PIL image, and must be used together with | ||
pixel_cut_high. To get reasonable values for arrays with dtype other | ||
than ``unit8`` this parameter is highly recommended. | ||
pixel_cut_high : number or ``None`` (the default) | ||
An optional value used to stretch the pixel values to the new range | ||
as defined by pixel_cut_low and pixel_cut_high. Only used if the | ||
image was not loaded as a PIL image, and must be used together with | ||
pixel_cut_low. To get reasonable values for arrays with dtype other | ||
than ``unit8`` this parameter is highly recommended. | ||
|
||
Returns | ||
------- | ||
An RGB :class:`PIL.Image.Image` representing a thumbnail of the input | ||
image. WWT thumbnails are 96 pixels wide and 45 pixels tall and should | ||
be saved in JPEG format. | ||
|
||
""" | ||
if self.mode in ( | ||
ImageMode.U8, | ||
ImageMode.I16, | ||
ImageMode.I32, | ||
ImageMode.F32, | ||
ImageMode.F64, | ||
ImageMode.F16x3, | ||
): | ||
raise Exception("cannot thumbnail-ify non-RGB Image") | ||
|
||
THUMB_SHAPE = (96, 45) | ||
THUMB_ASPECT = THUMB_SHAPE[0] / THUMB_SHAPE[1] | ||
|
||
|
@@ -1280,7 +1291,7 @@ def make_thumbnail_bitmap(self): | |
|
||
try: | ||
pil_image.MAX_IMAGE_PIXELS = None | ||
thumb = self.aspil().crop(crop_box) | ||
thumb = self.aspil(pixel_cut_low, pixel_cut_high).crop(crop_box) | ||
finally: | ||
pil_image.MAX_IMAGE_PIXELS = old_max | ||
|
||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stylistically, I like to have blank lines both before and after indenting constructs such as
for
,if,
etc.