# Copyright 2017 The TensorFlow Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== """The TensorBoard Images plugin.""" import imghdr import urllib.parse from werkzeug import wrappers from tensorboard import errors from tensorboard import plugin_util from tensorboard.backend import http_util from tensorboard.data import provider from tensorboard.plugins import base_plugin from tensorboard.plugins.image import metadata _IMGHDR_TO_MIMETYPE = { "bmp": "image/bmp", "gif": "image/gif", "jpeg": "image/jpeg", "png": "image/png", "svg": "image/svg+xml", } _DEFAULT_IMAGE_MIMETYPE = "application/octet-stream" _DEFAULT_DOWNSAMPLING = 10 # images per time series # Extend imghdr.tests to include svg. def detect_svg(data, f): del f # Unused. # Assume XML documents attached to image tag to be SVG. if data.startswith(b" sample ] def _filter_by_sample(self, tensor_events, sample): return [ tensor_event for tensor_event in tensor_events if ( len(tensor_event.tensor_proto.string_val) - 2 # width, height > sample ) ] def _query_for_individual_image(self, run, tag, sample, index): """Builds a URL for accessing the specified image. This should be kept in sync with _serve_image_metadata. Note that the URL is *not* guaranteed to always return the same image, since images may be unloaded from the reservoir as new images come in. Args: run: The name of the run. tag: The tag. sample: The relevant sample index, zero-indexed. See documentation on `_image_response_for_run` for more details. index: The index of the image. Negative values are OK. Returns: A string representation of a URL that will load the index-th sampled image in the given run with the given tag. """ query_string = urllib.parse.urlencode( { "run": run, "tag": tag, "sample": sample, "index": index, } ) return query_string def _data_provider_query(self, blob_reference): return urllib.parse.urlencode({"blob_key": blob_reference.blob_key}) def _get_generic_data_individual_image(self, ctx, blob_key): """Returns the actual image bytes for a given image. Args: blob_key: As returned by a previous `read_blob_sequences` call. Returns: A bytestring of the raw image bytes. """ return self._data_provider.read_blob(ctx, blob_key=blob_key) @wrappers.Request.application def _serve_individual_image(self, request): """Serves an individual image.""" try: ctx = plugin_util.context(request.environ) blob_key = request.args["blob_key"] data = self._get_generic_data_individual_image(ctx, blob_key) except (KeyError, IndexError): return http_util.Respond( request, "Invalid run, tag, index, or sample", "text/plain", code=400, ) image_type = imghdr.what(None, data) content_type = _IMGHDR_TO_MIMETYPE.get( image_type, _DEFAULT_IMAGE_MIMETYPE ) return http_util.Respond(request, data, content_type) @wrappers.Request.application def _serve_tags(self, request): ctx = plugin_util.context(request.environ) experiment = plugin_util.experiment_id(request.environ) index = self._index_impl(ctx, experiment) return http_util.Respond(request, index, "application/json")