# Help

## Tenmon help

Tenmon is intended primarily for viewing astro photos and images. It supports the following formats:

- FITS 8, 16, 32 bit integer and 32, 64 bit float
- XISF 8, 16, 32 bit integer and 32, 64 bit float
- JPEG, PNG, BMP, GIF, PBM, PGM, PPM and SVG images
- CR2, CR3, NEF, DNG raw images

### Main windows

The main window shows the currently loaded image. On the left is the Image info panel which displays details about the loaded image. The File system panel shows other images in the same directory as the loaded image. At the top is the main menu and below that is the Stretch panel containing various options for auto-stretching linear image data.

All panels in the interface can be moved around and/or closed. Any closed or non-visible panel can be re-opened through the Docks menu at the top.

At bottom there is status bar that show current lightness or red, green, blue pixel value under mouse cursor then X and Y coordinates and if image contain World Coordinate System metadata it show celestial coordinates.

### Opening and saving images

To load an image select File->Open and choose the file. After a file is loaded, it becomes visible in the main image panel, and the File system panel will show the other images in the same directory.

The loaded image can be exported to a different format with File->Save as. Any of the formats JPEG, PNG FITS and XISF can be selected. In the case of saving JPEG or PNG, the stretch function is applied to the saved image. FITS and XISF are saved/converted without applying the stretch. To open an image, you can also drag and drop it to main window.

### View

The View menu has options to control the size and scale of displayed images:

- Zoom In and Zoom Out magnify and shrink the image. The mouse wheel can be also used to zoom freely.
- Best fit auto-zooms the image to fit the current size of the window.
- 100% will zoom to 1:1 scale.
- Bayer mask set which bayer mask should be used when doing demosaicing.
- Colormap select color pallette when showing image with false colours.
- Fullscreen enlarges the main window to the whole screen.
- Thumbnails will display small thumbnails for all images in the current directory.
- Slideshow start showing all images periodically with interval that can be set in settings.

Colormap can also be user defined. Place image file named colormap.png into application data directory. On Windows"C:/Users/<USER>/AppData/Roaming/nou/Tenmon" Linux: "~/.local/share/nou/Tenmon/" MacOS: "~/Library/Application Support/nou/Tenmon/" This image should be 256 pixel wide. Each row of image will be used as separate color map and added to Colormap menu.

### Stretch toolbar

This panel changes how images are displayed.

Starting on the left, there is slider scale with three adjustable points to manually control the stretch.

- black point - all pixels with lower value (darker) than this setting will be clipped black
- mid point - defines the value to be stretched to 50% intensity
- white point - all pixels with higher value (brighter) than this will be clipped white

Following the slider are 8 buttons to control image display:

- Linked channels toggle stretching each RGB channel individually.
- Auto Stretch automatically apply black and mid points to render the image with optimal brightness.
- Reset reset three values for black, mid and white point to default.
- Invert invert colors to display the image as negative.
- False colors show black and white in false colour palette.
- Debayer CFA Demosaicing black and white image from CFA sensor to color one.
- Apply Auto stretch on load toggle automatically applying Autostretch for each image when loaded.
- Draw equatorial grid toggle drawing equatorial coordinate grid and catalogue objects. Needs that file have WCS data.

### Marking images

Images can be marked in the Select menu. To show a list of only the marked images, use Select->Show marked. This dialog can be useful to clear marks from images. Marked images show a * character in the title bar of the main window. Marked images can be copied or moved to a selected directory with File->Copy/Move marked files. After copying or moving, the list of marked files is cleared. The list of marked files will be remembered after quitting the program.

Another way to mark images is in database view where you can select rows and then select mark or unmark action in context menu. Marked files will be shown with bold text. Third way to mark files is from thumbnails view where you can press press Shift and click with left mouse button and drag across thumbnails to mark them. Holding Ctrl will unmark files.

### File system and tree

File system panel contain list of images in current opened directory. You can select file from this list and it will be displayed. It is also possible to use arrow keys to go back (left and up) and forth (right and down) between images.

File tree show file system structure. You can right click to show context menu to perform various actions from File menu. There are also few others

- Set as root directory show only this directory and subdirectories
- Reset root directory show whole file system
- Go up show directory that is one level above current root directory

### Database of FITS/XISF files

Tenmon can scan a directory of FITS/XISF files and index metadata from FITS headers into it's internal database. This allows searching and sorting images based on that metadata.

To populate the database, select a directory of FITS/XISF files with File->Index directory. After the selected directory is searched, metadata parsed from the images will be stored in the database. To refresh the database, run File->Reindex. This will update any changed metadata and remove any record of deleted files. To index new files, simply run Index directory again.

The database is viewed through a panel which is not visible in the default layout. To add the database panel to the view, toggle Docks->FITS/XISF database. Once visible, database panel shows the database as a table with a column for each property. Below the table is button to select which columns/properties are displayed.

Also at the bottom of the database panel are three combo boxes and text inputs used for filtering. Select the property to filter on with the combo box and in the adjacent text box enter a string to search for in that property. These three combo box contain list of all properties that are found during indexing except first five. First one set searching in file name. Next two "RA pos" and "DEC pos" allow to filter out indexed images that contain point with entered RA/DEC coordinate. Expected format is three number separated by space. In case of "DEC pos" it also accept +- sign. Omitting one or two last number is also valid. Some examples "02 12 32" "-12 43 12" "+45 32" "13". So for RA it means hour, minutes and seconds while for DEC it is degrees, minutes and seconds. Setting both "RA pos" and "DEC pos" can return images that doesn't contain entered point as it search against minimum and maximum RA/DEC coordinates that images contain. "RA range" and "DEC range" filter out images which center coordinate is within entered range. Pressing Enter or clicking on Filter button will filter out database record according to search parameter.

Wildcards:

- % (percent) is a wildcard representing zero or more of any characters.
- _ (underscore) is a wildcard for exactly one of any character.
- Without wildcard characters, the exact string must match.

This example filters for files where: "Bias" is in the file name, the OBJECT property is "M_42" (where the underscore can be any single character), and the DATE property begins with "2022".

### Plate Solving

This module can plate solve images and update FITS header with solution for FITS and XISF images. Profile this set various parameters that affect star extraction and solving. Starting point program will try to automatically determine optimal starting point which helps to speed up solving. You can leave one or both unchecked then it will attempt to do blind solving. If the position or scale is wrong it can actually fail to solve. Solution this section contain resulting solution like RA,DEC coordinates center of image, image field of view, orientation as degrees E of N, image scale in arcseconds per pixel, number of stars extracted and HFR fitting and eccentricity. Then there is log window for debug information from solver.

Then finally there are various action button. Settings button show dialog where you can set path to existing index files or auto download some. Extract button will just extract stars from image and it will show their count, HFR and eccentricity. This action doesn't need index files. Solve button will try to find coordinates of images. Abort button will stop extraction or solving. Update FITS header will update FITS fits keywords with found solution.

In settings dialog you can set path to index files which is by default custom internal one. It also try to locate commonly used path from other programs like KStars for astrometry.net index files.

### File Manager

This is simple double panel file manager. It can show columns with selected FITS keywords. Each panel have tabs where it easily switch between multiple directories. You can copy or move files and directories either inside one panel or between two panels by selecting and then dragging. By default files are copies. To move then press Shift key before start dragging. Double click on file will open it in main window if it is image or other file it will open default program that is associated with it this file type. You can also drag file to other programs like from default file explorer programs that are in system or from file explorer to this program.

In menu you can select which FITS keywords will be showed. Temporarilly disable loading FITS header or copy file paths of selected files as text.

### Batch processing

This module allow to write scripts in JavaScript that process image files. Batch Processing window consist from three main parts. On top is list of input files and directories. You can add directories or individual files to this list. Directories are scanned recursively to find all files even non image files. This list of files is then passed to script in array named files. In script you can then iterate through files like this.

    for(file of files)
    {
        if(file.suffix() == "fits")
        {
            core.log(file.fileName());
            file.convert(file.relativeFilePath(), "XISF");
        }
    }

Bellow this list is output directory. All relative paths passed as arguments into methods like copy(), move() or convert() will be relative to this output directory. If you pass absolute path to methods then this output directory is ignored.

Bellow that is list of scripts. These scripts are located in application data directory. Select script which you want to run by clicking on it. Clicking on Open scripts will open directory with these scripts where you create new and edit them. Location of this directory is on Windows: "C:/Users/<USER>/AppData/Roaming/nou/Tenmon/scripts" Linux: "~/.local/share/nou/Tenmon/scripts" MacOS: "~/Library/Application Support/nou/Tenmon/scripts"

Next is Log windows that contain any messages that come from scripts. Mainly calls to `core.log()` At bottom there is console that enable run simple script commands and buttons that can start or stop execution of selected scripts.

#### core

There is global object called core that have these methods.

- log(message) print message to log window.
- mark(file) mark file same way as in GUI. Takes object of type File as argument.
- unmark(file) unmark file same was as in GUI. Takes object of type File as argument.
- isMarked(file) check if file was marked. Takes object of type File as argument.
- setMaxThread(maxthread) set maximum number of concurrent thread when doing asynchronous task.
- sync() wait until all asynchronous tasks are done.
- getString(label = "", text = "") show dialog box to get string value from user. String value passed in first argument is used as description label. Second argument text is default value in text box. Both parameters are optional so calling just getString() is valid. When cancel is pressed it return Undefined.
- getInt(label = "", value = 0) show dialog box with input box to retrieve integer value. String value passed in first argument is used as description label. Second parameter is default value in input box. Both parameters are optional. When cancel is pressed it return Undefined.
- getFloat(label = "", value = 0, decimals = 3) show dialog box with input box to retrieve decimal value. String value passed in first argument is used as description label. Second parameter is default value in input box. All three parameters are optional. When cancel is pressed it return Undefined.
- getItem(items) show selection dialog which allow to select one item from array of items. It return selected item as string. When cancel is pressed it return Undefined.
- setStartingSolution(solution) with this you can set starting point and image scale. It accepth object with attributes "ra", "dec", "pixscale". Same object as returned by File.solve() method. You can also call it without paramer in which case it will clear any previously set values.
- getSolverProfile() return solver profile as Object.

      var profile = core.getSolverProfile();
      core.log(JSON.stringify(profile));

- setSolverProfile(index) set solver profile by index. Valid values are from 1 to 8 as in GUI.
- setSolverProfile(profile) set solver profile. Parameter is same as object returned by getSolverProfile() method
- question(question, buttons, title = "") show dialog with question. First argument question is string. Second argument buttons is array of following strings. "ok", "yes", "no", "yesall", "noall", "abort", "retry", "ignore", "cancel", "discard", "apply", "reset" Third argument title is optional string that show in title bar. It return button that was clicked as a string.

      var button = core.question("Apply to all files?", ["yes", "no"]);

- plot(graph) this method show graph defined by JS object.

      var chart = {
          "title": "Chart title", // Title that will show on top of chart
          "legend":
          {
              "visible": true,// default is true
              "align": "left" // allowed values are "top", "right", "bottom", "left". default is "top"
          },
          "series":[ // array of data series
              {
                  "title": "HFR",
                  "type": "bar", // type of the serie. Can be one of "line", "points", "linePoints", "bar"
                  "y":[2.5,3.1,2.6,2.2] // array of values
              },
              {
                  "title": "Ecc",
                  "y":[0.37, 0.4, 0.35, 0.25],
                  "color": "red" // color of serie. It can be name of color like "green" or RGB hex value "#ccddff"
              },
              {
                  "title": "Stars",
                  "type": "points", // type of serie. can be "line", "points", "linePoints" and "bar". Default is "line"
                  "shape": "star", // shape of markers. valid only for points
                  "x":[1, 2.5, 3.5, 6],// line, points and linePoints can also have "x" values. Otherwise it assume sequence 0,1,2 ...
                  "y":[523,412,487,510],
                  "y2": true, // if set to true this serie will use secondary Y axis
                  "bestFit": true, // show best fit line
                  "color": "#0000ff"
              }
          ]
      };

      core.plot(chart);

#### File

In files array there are instances of type File objects that have these methods.

- fileName() returns the name of the file, excluding the path.
- absoluteFilePath() returns an absolute path including the file name.
- absolutePath() returns an absolute path without the file name
- relativeFilePath() return relative path including file name relative to directory that was in list of directories to be scanned. For example you add C:/images as input directory. In this directory there is file C:/images/lights/red/M42_001.fits then this method will return lights/red/M42_001.fits
- relativePath() return same path as previous method just without file name. lights/red
- baseName() return file name up to the first dot. For example for some.file.name.fits it will return some
- completeBaseName() return file name up to the last dot. For example for some.file.name.fits it will return some.file.name
- suffix() return string after last dot in file name. For example fits
- size() return size of file in bytes.
- fitsKeywords() return array of strings with every keyword that is in header. SIMPLE,BITPIX,NAXIS,NAXIS1,NAXIS2,EXTEND,COMMENT
- fitsValue(key) return value for keyword. In case that there is multiple occurrences it return last one.
- fitsValues(key) return array of values for keyword.
- fitsRecords() return array of objects with properties key, value and comment
- modifyFITSRecords(FITSRecordModify) modify FITS header by adding, removing or updating FITS record. Return true on success. Refer to FITSRecordModify
- isMarked() return true if file is marked.
- copy(newpath) copy file to new location. It return instance of new File object that represent this copied file. This path can be relative or absolute. In case that newpath parameter is relative path then it "Output directory" from GUI windows is used as base directory. Parameter newpath can absolute path. File is then copied to this path. In case that copy fail it return null.
- move(newpath) move file to new location. It return false if move failed. This can happend if destination is not writable but also if destination file already exist. This functions does not overwrite existing file. This path can be relative or absolute. In case that newpath parameter is relative path then it "Output directory" from GUI windows is used as base directory. Parameter newpath can be absolute path. File is then moved to this path.
- convert(outpath, format, params) convert image file from any format that program is able to open into FITS, XISF, JPEG, PNG, BMP. Parameters are: outputpath path where converted image will be saved. It automatically replace suffix according to format. This method return new instance of File that point to converted file. format one of "FITS" "XISF", "JPG", "PNG", "TIFF" or "BMP". params object with attributes
  - "compressionLevel" used with XISF format. integer value between 0-100 determining speed and compression ratio.
  - "compressionType" for FITS format it can be "gzip" and "rice". For XISF it can be "zlib", "lz4", "lz4hc", "zstd", "zlib+sh", "lz4+sh", "lz4hc+sh", "zstd+sh"
  - "binning" any integer value above 1 will perform integer downsample
  - "average" by default set to true. If you set to false it will sum pixel values instead of averaging when performing binning.
  - "resize" downsample image to defined width and height by subobject `"resize":{"width": 128, "height": 128, "aspect":"keep"}` "aspect" determine how to handle aspect ration when resizing image. "keep" and "expand" preserve original aspect ratio. Difference is that "keep" resulting image will be at most requested size "epand" resulting size will be at least requested size. For example input image 800x600 pixels and resizing to 128x128. With keep resulting image will be 128x96 while with epxand it will be 170x128. If set to "ignore" then resulting image will be exact size 128x128 ignoring original aspect ratio. By default keep is used.
  - "autostretch" when set to true it apply automatic stretch function to pixel values. By default it is set to false.
  In case that both binning and resizing is set binning is performed first then resing.

      file.convert("converted_file.xisf", "xisf", {"compressionType": "zstd+sh", "compressionLevel": 70});
      file.convert("converted_file.fits", "fits", {"compressionType": "rice"});
      file.convert("converted_file.jpg", "png");
      file.convert("thumbnail.jpg", "jpg", {"binning": 2, "average": true, "resize": {"width":256, "height": 256, "aspect":"ignore"}, "autostretch": true});

- convertAsync(outpath, format, params) same as previous method but it does conversion in separated thread asynchronously and in parallel. Before calling any method on object returned by this method you must call `core.sync();` to ensure that conversion is done and destination file exists.

      let compression = {"compressionType": "zstd+sh"};
      let convertedFiles = [];
      for(file in files)
      {
          if(file.suffix() == "fits")
              convertedFiles.push(file.convertAsync("xisf/" + file.fileName(), "XISF", compression));
      }
      core.sync(); // ensure that files exist
      for(file of convertedFiles)// now we can iterate over the files
      {
          core.log(file.fileName() + " " + file.size()); // let print compressed file sizes
      }

- stats() calculate basic images statistics and return them as object with attributes "mean", "stddev", "median", "min", "max" and "mad".

      let s = file.stats();
      core.log("Median value is " + s.median);

- solve(updateHeader) this method will run plate solving on this image and will return solution in form of object with these attributes "ra" and "dec" which are center coordinates of image "fieldWidth" and "fieldHeight" which is FOV of image in arcseconds, "orientation" is degrees east of north, "pixscale" scale of image in arcseconds per pixel, "parity" true false value if the image was flipped in vertical direction, "raError" and "decError" deviation from starting point. When updateHeader is set to true it update FITS header for file with this solution. Default value is false.
- extractStars(hfr) extract stars will run extraction of stars. When parameter hfr is set to true it will fit HFR on every star. It return array of objects representing extracted stars. Each object in array will have these attributes "x" and "y" pixel coordinates of center of star, "mag" relative magnitude of star, "flux" total flux, "peak" peak value of star, "HFR" half flux radius of star, "a" and "b" semi major and minor axis of star, "theta" angle of orientation of the star, "ra" and "dec" coordinates of star, "numPixels" number of pixel occupied by the star in image.

#### FITSRecordModify

This class is used to define modify operation FITS header in FITS and XISF files. It can remove update and add records. Order of operation is also remove then update and last add. The keyword names may be up to 8 characters long and can only contain uppercase letters, the digits 0-9, the hyphen, and the underscore character.

    let modify = new FITSRecordModify();
    modify.updateKeyword("OBJECT", "M42");
    modify.updateKeyword("MYTILE", "PART1", "adding custom keyword so WBPP can group it");
    modify.removeKeyword("OBJECT");
    // doesn't matter that it is specified as last. This will first remove
    // existing OBJECT record and then add again OBJECT=M42
    for(file in files)
    {
        file.modifyFITSRecords(modify);
    }

- new FITSRecordModify() create new instance of object.
- removeKeyword(key); specify removing of record with key as keyword.
- updateKeyword(key, value, comment = "") specify updating existing keyword with value and comment. Comment is optional parameter. If record with keyword doesn't exist then it will add new one. Unless you want to have multiple records with same keyword (for example HISTORY) always use this method and not addKeyword.
- addKeyword(key, value, comment = "") specify adding new keyword

PS: Kanji in icon means astronomy in Japanese