Mercurial > hg > octave-lojdl
view libinterp/corefcn/txt-latex.cc @ 17436:d415dc6ac1e2
Added horizontal/vertical alignment and rotation to latex_render class
author | Andrej Lojdl <andrej.lojdl@gmail.com> |
---|---|
date | Tue, 17 Sep 2013 16:20:47 +0200 |
parents | 71b6f8a81e80 |
children | fd3e999305ea |
line wrap: on
line source
/* Copyright (C) 2013 Andrej Lojdl This file is part of Octave. Octave is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Octave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Octave; see the file COPYING. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <iostream> #include <fstream> #include <string> #include <cstdlib> #include <cstring> #include <sstream> #ifdef ENABLE_LATEX #include <png.h> #include "error.h" #include "txt-latex.h" #include "oct.h" #include "dim-vector.h" #include "file-ops.h" latex_render::latex_render (void) : bbox (1, 4, 0.0), color (dim_vector (1, 3), 0) { } latex_render::~latex_render (void) { } int latex_render::check_programs (void) { int cmd, ready = 1; std::string check_latex, check_dvips, check_ghostscript; check_latex = "latex --version >/dev/null 2>/dev/null"; check_dvips = "dvips --version >/dev/null 2>/dev/null"; check_ghostscript = "gs --version >/dev/null 2>/dev/null"; cmd = system (check_latex.c_str ()); if (cmd != 0) { ::error("There's no LaTeX document preparation system installed on this system. Please install it and then try again."); ready = 0; } cmd = system (check_dvips.c_str ()); if (cmd != 0) { ::error("There's no dvips converter installed on this system. Please install it and then try again."); ready = 0; } cmd = system (check_ghostscript.c_str ()); if (cmd != 0) { ::error("There's no GhostScript program for converting installed on this system. Please install it and then try again."); ready = 0; } return ready; } void latex_render::adapter (const std::string& txt) { std::ofstream file; std::string directory_name = "latex", tex; int status; /* Creating unique name of directory - this function should use temporary files on every system*/ directory_path = octave_tempnam ("", directory_name); /* Creating the directory */ status = octave_mkdir (directory_path, 0700); /*Check if directory is created successfully. */ if (status == 0) { /* Pointing to temporary directory, for creating .tex file */ tex = file_ops::concat (directory_path, "default.tex"); /* Creating and writing to temporary .tex file */ file.open (tex.c_str ()); file << "\\documentclass[fleqn]{article} \n\\usepackage{amsmath} \n\\usepackage{color} \n\\pagestyle{empty} \n\\begin{document} \n\t\\fontsize{12pt}{12pt}\\selectfont \n\t"; file << "\\usefont{T1}{" << font_name << "}{m}{n} \n\t\t"; file << txt; file << "\n\\end{document}"; file.close (); } else { /* Printing error if directory is not created */ ::error ("Failed to create temp directory."); std::cout << error_state << std::endl; } } uint8NDArray latex_render::render (void) { int status; std::stringstream ss; std::string comment, string_font_size; uint8NDArray data; std::ifstream file; std::string sfsize, tex, aux, log, dvi, eps, png, command; /* Check if command processor is available */ if(system (NULL) && error_state == 0) { log = file_ops::concat (directory_path, "default.log"); tex = file_ops::concat (directory_path, "default.tex"); command = "latex -interaction=nonstopmode -output-directory=" + directory_path + " " + tex + " > " + log; /* .tex -> .dvi */ status = system (command.c_str ()); if(status != 0) { data = uint8NDArray (dim_vector (4, 1, 1), static_cast<uint8_t> (0)); ::error ("LaTeX converting .tex to .dvi file, failed."); file.open (log.c_str ()); for(int i=0; i<33; i++) { std::getline (file, comment); } /* Print additional info from default.log */ comment = "Here is LaTeX description of error:"; std::cout << comment << std::endl; std::getline (file, comment); std::cout << comment << std::endl; std::getline (file, comment); std::cout << comment << std::endl; file.close (); return data; } /* .dvi -> .eps */ dvi = file_ops::concat (directory_path, "default.dvi"); eps = file_ops::concat (directory_path, "default.eps"); command = "dvips " + dvi + " -E -o " + eps + " -q"; status = system (command.c_str ()); if(status != 0) { data = uint8NDArray (dim_vector (4, 1, 1), static_cast<uint8_t> (0)); ::error ("dvips converting .dvi to .eps file file, failed"); return data; } /* .eps -> .png */ font_size = font_size * (72 / 12); ss << font_size; ss >> string_font_size; png = file_ops::concat (directory_path, "default.png"); command = "gs -q -dEPSCrop -dSAFER -dBATCH -dNOPAUSE -r" + string_font_size + " -dTextAlphaBits=4 -sDEVICE=pngalpha -sOutputFile=" + png + " \"" + eps + "\" "; status = system (command.c_str ()); if(status != 0) { data = uint8NDArray (dim_vector (4, 1, 1), static_cast<uint8_t> (0)); ::error ("GhostScript converting .eps to .png file, failed"); return data; } /* Read image from PNG file */ int x; int y; int width, height; png_byte color_type; png_byte bit_depth; png_structp png_ptr; png_infop info_ptr; int number_of_passes; png_bytep * row_pointers; char header [8]; /* Open file and test for it being a png */ FILE *fp = fopen (png.c_str (), "rb"); if (!fp) { ::error ("File default.png could not be opened for reading"); } fread (header, 1, 8, fp); /* Initialize stuff */ png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { ::error ("png_create_read_struct failed"); } info_ptr = png_create_info_struct (png_ptr); if (!info_ptr) { ::error ("png_create_info_struct failed"); } if (setjmp (png_jmpbuf (png_ptr))) { ::error ("Error during init_io"); } png_init_io (png_ptr, fp); png_set_sig_bytes (png_ptr, 8); png_read_info (png_ptr, info_ptr); width = png_get_image_width (png_ptr, info_ptr); height = png_get_image_height (png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth (png_ptr, info_ptr); number_of_passes = png_set_interlace_handling (png_ptr); png_read_update_info (png_ptr, info_ptr); /* Read file */ if (setjmp (png_jmpbuf (png_ptr))) { ::error ("Error during read_image"); } row_pointers = (png_bytep*) malloc (sizeof (png_bytep) * height); for (y=0; y<height; y++) row_pointers[y] = (png_byte*) malloc (png_get_rowbytes (png_ptr, info_ptr)); png_read_image (png_ptr, row_pointers); fclose (fp); /* Instantise data array */ data = uint8NDArray (dim_vector (4, width, height), static_cast<uint8_t> (0)); for (int i=0; i<height; i++) { png_byte* row = row_pointers[height - 1 - i]; for (int j=0; j<width; j++) { png_byte* ptr = &(row[j * 4]); /* If the color of text is black we can change it, if not we render the original color. */ if(ptr[0] < 50 && ptr[1] < 50 && ptr[2] < 50 ) { data(0, j, i) = color(0); data(1, j, i) = color(1); data(2, j, i) = color(2); data(3, j, i) = ptr[3]; } else { data(0, j, i) = ptr[0]; data(1, j, i) = ptr[1]; data(2, j, i) = ptr[2]; data(3, j, i) = ptr[3]; } } } /* Remove the temporary directory. */ if( !directory_path.empty ()) status = octave_recursive_rmdir (directory_path); } else { /* It's possible that command procesor is not available and we already made a temporary dir*/ if( !directory_path.empty ()) status = octave_recursive_rmdir (directory_path); data = uint8NDArray (dim_vector (4, 1, 1), static_cast<uint8_t> (0)); if(error_state == 1) ::warning ("LaTeX interpreter can't proceed, please try again."); else ::warning ("Command processor not ready yet, please try again."); } return data; } void latex_render::set_font (const std::string& name, const std::string& weight, const std::string& angle, double size) { font_size = size; if(name[0] == '*') font_name = "cmr"; else font_name = name; } void latex_render::set_color (Matrix c) { if (c.numel () == 3) { color(0) = static_cast<uint8_t> (c (0) * 255); color(1) = static_cast<uint8_t> (c (1) * 255); color(2) = static_cast<uint8_t> (c (2) * 255); } else ::warning ("latex_render::set_color: invalid color"); } int latex_render::rotation_to_mode (double rotation) const { if (rotation == 0.0) return ROTATION_0; else if (rotation == 90.0) return ROTATION_90; else if (rotation == 180.0) return ROTATION_180; else if (rotation == 270.0) return ROTATION_270; else return ROTATION_0; } void latex_render::text_to_pixels (const std::string& txt, uint8NDArray& pixels, Matrix& bbox, int halign, int valign, double rotation) { if (check_programs () == 1) { adapter (txt); pixels = render(); } else { pixels = uint8NDArray (dim_vector (4, 10, 10), static_cast<uint8_t> (0)); } if(pixels.ndims () < 3) ::warning ("Pixels variable not properly set."); else { bbox = Matrix (1, 4, 0.0); bbox (2) = pixels.dim2 (); bbox (3) = pixels.dim3 (); switch (halign) { default: bbox(0) = 0; break; case 1: bbox(0) = -bbox(2)/2; break; case 2: bbox(0) = -bbox(2); break; } switch (valign) { default: bbox(1) = 0; break; case 1: bbox(1) = -bbox(3)/2; break; case 2: bbox(1) = -bbox(3); break; case 3: break; case 4: bbox(1) = -bbox(3)-bbox(1); break; } int rot_mode = rotation_to_mode (rotation); switch (rot_mode) { case ROTATION_90: std::swap (bbox(0), bbox(1)); std::swap (bbox(2), bbox(3)); bbox(0) = -bbox(0)-bbox(2); break; case ROTATION_180: bbox(0) = -bbox(0)-bbox(2); bbox(1) = -bbox(1)-bbox(3); break; case ROTATION_270: std::swap (bbox(0), bbox(1)); std::swap (bbox(2), bbox(3)); bbox(1) = -bbox(1)-bbox(3); break; } } /* Rotating pixels */ int rot_mode = rotation_to_mode (rotation); if (pixels.numel () > 0) { switch (rot_mode) { case ROTATION_0: break; case ROTATION_90: { Array<octave_idx_type> perm (dim_vector (3, 1)); perm(0) = 0; perm(1) = 2; perm(2) = 1; pixels = pixels.permute (perm); Array<idx_vector> idx (dim_vector (3, 1)); idx(0) = idx_vector (':'); idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1); idx(2) = idx_vector (':'); pixels = uint8NDArray (pixels.index (idx)); } break; case ROTATION_180: { Array<idx_vector> idx (dim_vector (3, 1)); idx(0) = idx_vector (':'); idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1); idx(2)= idx_vector (pixels.dim3 ()-1, -1, -1); pixels = uint8NDArray (pixels.index (idx)); } break; case ROTATION_270: { Array<octave_idx_type> perm (dim_vector (3, 1)); perm(0) = 0; perm(1) = 2; perm(2) = 1; pixels = pixels.permute (perm); Array<idx_vector> idx (dim_vector (3, 1)); idx(0) = idx_vector (':'); idx(1) = idx_vector (':'); idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1); pixels = uint8NDArray (pixels.index (idx)); } break; } } } Matrix latex_render::get_extent (text_element *elt, double rotation) { Matrix extent (1, 2, 0.0); return extent; } Matrix latex_render::get_extent (const std::string& txt, double rotation) { text_element *elt = text_parser_none ().parse (txt); Matrix extent = get_extent (elt, rotation); delete elt; return extent; } #endif //ENABLE_LATEX