Files
Tools_CPP/lib/wxCairo.cpp
2024-11-01 12:23:13 +05:00

428 lines
14 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/***************************************************************
* Name: wxCairo.cpp
* Purpose: Code for Application Frame
* Author: Igor I (info@tiptopcity.com)
* Created: 2009-05-24
* Copyright: Igor I (www.tiptopcity.com)
* License:
**************************************************************/
#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif
//------------------------------------------------------------------------------
//#include <cairo/cairo-svg.h>
//#include <librsvg/rsvg.h>
//#include <librsvg/rsvg-cairo.h>
#if defined(_WIN32) || defined(_WINDOWS) || defined(_BORLAND) || defined(__BORLANDC__)
#include <cairo/cairo-win32.h>
#else
#endif
#include <cairo/cairo.h>
//#include <librsvg/rsvg.h>
//#include <librsvg/rsvg-cairo.h>
//#include <svg_cairo.c>
#include <math.h>
#include <string.h>
#include "wxCairo.h"
#include "stdTools.h"
//#include "wxgui/debug.h"
//------------------------------------------------------------------------------
struct stdword{
std::string str;
int width;
};
//------------------------------------------------------------------------------
wxCairo::wxCairo()
{
glId=0;
m_buffer=NULL;
m_surface=NULL;
m_cr=NULL;
m_format = CAIRO_FORMAT_RGB24;
m_width=0; m_height=0;
}
//------------------------------------------------------------------------------
wxCairo::~wxCairo()
{
if(m_buffer!=NULL) delete m_buffer;
if(m_surface!=NULL) cairo_surface_destroy(m_surface);
if(m_cr!=NULL) cairo_destroy(m_cr);
}
//------------------------------------------------------------------------------
unsigned char* wxCairo::CreateBuffer(int width,int height)
{
if(width!=m_width || m_height!=height)
{
if(m_buffer!=NULL) delete m_buffer;
m_width=width; m_height=height;
m_buffer = new unsigned char[width*height*4]; //RGBA
memset(m_buffer, 0, width*height*4); //Обнулим массив
Init();
return m_buffer;
}else
{
memset(m_buffer, 0, width*height*4); //Обнулим(отчистим) массив
return m_buffer;
}
}
//------------------------------------------------------------------------------
bool wxCairo::Init()
{
if(m_surface!=NULL) cairo_surface_destroy(m_surface);
if(m_cr!=NULL) cairo_destroy(m_cr);
m_surface = cairo_image_surface_create_for_data(m_buffer, m_format, m_width, m_height, m_width*4);
m_cr = cairo_create(m_surface);
cairo_set_antialias(m_cr, CAIRO_ANTIALIAS_NONE);
return true;
}
//------------------------------------------------------------------------------
/*void wxCairo::Draw(wxPaintDC& dc)
{
// Convert from Cairo RGB24 format to wxImage BGR format.
unsigned char *dRGB = new unsigned char[m_width*m_height*3];
//unsigned char *dA = new unsigned char[m_width*m_height];
for(int y=0;y<m_height;y++)
{
for(int x=0;x<m_width;x++)
{
dRGB[x*3+y*m_width*3] = m_buffer[x*4+2+y*m_width*4];
dRGB[x*3+1+y*m_width*3] = m_buffer[x*4+1+y*m_width*4];
dRGB[x*3+2+y*m_width*3] = m_buffer[x*4+y*m_width*4];
//dA[x*y] = 255;
}
}
// Blit final image to the screen.
//wxImage img=wxImage(m_width, m_height, dRGB, dA, true);
wxImage img=wxImage(m_width, m_height, dRGB, true);
//if(img.HasAlpha())
//{
wxBitmap m_bitmap(img);
dc.DrawBitmap(m_bitmap, 0, 0, true);
//}
delete dRGB;
//delete dA;
}*/
//------------------------------------------------------------------------------
//Нарисуем чтонибудь для примера в текущем буфере
bool wxCairo::Test()
{
// White background.
//cairo_set_source_rgb(m_cr, 1.0, 1.0, 1.0);
//cairo_rectangle(m_cr, 0, 0, m_width, m_height);
//cairo_fill(m_cr);
//draw stuff
cairo_select_font_face(m_cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(m_cr, 32.0);
cairo_set_source_rgb(m_cr, 0.0, 0.0, 1.0);
cairo_move_to(m_cr, 10.0, 50.0);
std::string str="Привет мир!";
//const wxCharBuffer buff = str.mb_str(wxConvUTF8);
cairo_show_text (m_cr, str.c_str());
//Curve
double x=25.6, y=128.0;
double x1=102.4, y1=230.4,
x2=153.6, y2=25.6,
x3=230.4, y3=128.0;
cairo_move_to (m_cr, x, y);
cairo_curve_to (m_cr, x1, y1, x2, y2, x3, y3);
cairo_set_line_width (m_cr, 10.0);
cairo_stroke (m_cr);
cairo_set_source_rgba (m_cr, 1, 0.2, 0.2, 0.6);
cairo_set_line_width (m_cr, 6.0);
cairo_move_to (m_cr,x,y); cairo_line_to (m_cr,x1,y1);
cairo_move_to (m_cr,x2,y2); cairo_line_to (m_cr,x3,y3);
cairo_stroke (m_cr);
//SVG
/*cairo_surface_t *surface;
//cairo_t *cr;
surface = cairo_svg_surface_create("Svg.svg", 390, 60);
cr = cairo_create(surface);
cairo_set_source_rgb(m_cr, 0, 0, 0);
cairo_select_font_face (m_cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (m_cr, 40.0);
cairo_move_to(m_cr, 10.0, 50.0);
cairo_show_text(m_cr, "Disziplin ist Macht.");
cairo_surface_destroy(surface);
//cairo_destroy(cr);*/
/*double IMAGE_WIDTH = 256;
double IMAGE_HEIGHT = 256;
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, IMAGE_WIDTH, IMAGE_HEIGHT);
cairo_t* cr = cairo_create(surface);
cairo_scale(cr, IMAGE_WIDTH, IMAGE_HEIGHT);
svg_cairo_t* svgc;
svg_cairo_create(&svgc);
gtk_init(&argc, &argv); // 1) doesn't work
svg_cairo_parse(svgc, "data/home.svg");
// gtk_init(&argc, &argv); // 2) works
unsigned w, h;
svg_cairo_get_size(svgc, &w, &h);
cairo_scale(cr, 1.0 / w, 1.0 / h);
svg_cairo_render(svgc, cr);
svg_cairo_destroy(svgc);
cairo_surface_write_to_png(surface, "out.png");
cairo_destroy(cr);
cairo_surface_destroy(surface);
return 0;*/
return true;
}
//------------------------------------------------------------------------------
void wxCairo::MoveTo(double x, double y)
{
cairo_move_to(m_cr,x,y);
}
//------------------------------------------------------------------------------
void wxCairo::LineTo(double x, double y)
//void wxCairo::LineTo(double y, double x)
{
cairo_line_to(m_cr,x,y);
}
//------------------------------------------------------------------------------
void wxCairo::SetLineWidth(double width)
{
cairo_set_line_width(m_cr, width);
}
//------------------------------------------------------------------------------
void wxCairo::ShowText(std::wstring& str)
{
std::string utf8=convUTF16ToUTF8(str);
cairo_show_text (m_cr, utf8.c_str());
}
//------------------------------------------------------------------------------
void wxCairo::SetSourceRGBA(double red, double green, double blue, double alpha)
{
cairo_set_source_rgba(m_cr, red, green, blue, alpha);
}
//------------------------------------------------------------------------------
void wxCairo::SetSourceRGB(double red, double green, double blue)
{ cairo_set_source_rgb(m_cr, red, green, blue);
}
//------------------------------------------------------------------------------
void wxCairo::Rectangle (double x, double y, double width, double height)
{ cairo_rectangle (m_cr, x, y, width, height);
}
//------------------------------------------------------------------------------
//Не рисовать то что не входит в последний геом объект
void wxCairo::Clip()
{ cairo_clip(m_cr);
}
//------------------------------------------------------------------------------
void wxCairo::ResetClip()
{ cairo_reset_clip(m_cr);
}
//------------------------------------------------------------------------------
void wxCairo::Fill()
{ cairo_fill(m_cr);
}
//------------------------------------------------------------------------------
//Обводка
//Операция cairo_stroke() применяет виртуальный карандаш вдоль контура.Это позволяет источнику передать через маску тонкую(или толстую) линию вдоль контура, в соответствие с карандашной толщиной линии, стилем точек, и наконечниками линии.
void wxCairo::Stroke()
{ cairo_stroke(m_cr);
}
//------------------------------------------------------------------------------
//Преобразовать рисунок в битовый массив
void wxCairo::toBitArray(unsigned char* bitArray)
{
int pos = 0;
for (int y = 0; y<m_height; y++)
{
for (int x = 0; x<m_width; x++)
{
unsigned char r = m_buffer[x * 4 + 2 + y*m_width * 4];
unsigned char g = m_buffer[x * 4 + 1 + y*m_width * 4];
unsigned char b = m_buffer[x * 4 + y*m_width * 4];
unsigned char px = (r + g + b) / 3.0f;
int posB=floor(pos / 8.0f); //Номер байта
if (px < 127) //Чёрный это 1
{
setBit(&bitArray[posB], pos - posB * 8, true);
//
}else //Белый это 0
{
setBit(&bitArray[posB], pos - posB * 8, false);
}
pos++;
}
}
}
//------------------------------------------------------------------------------
void wxCairo::setBit(unsigned char *mas, const unsigned char pos, bool val)
{
unsigned char mask = 128;
unsigned char loc = pos / 8;
mask = mask >> (pos - loc * 8);
if (val) mas[loc] = mas[loc] | mask;
else
{
mask = ~mask; //Отрицание
mas[loc] = mas[loc] & mask;
}
}
//------------------------------------------------------------------------------
void wxCairo::setFontface(std::string family,bool slant,bool weight)
{
cairo_font_slant_t s;
if (slant) s = CAIRO_FONT_SLANT_ITALIC; else s = CAIRO_FONT_SLANT_NORMAL;
cairo_font_weight_t w;
if (weight) w = CAIRO_FONT_WEIGHT_BOLD; else w = CAIRO_FONT_WEIGHT_NORMAL;
cairo_select_font_face(m_cr,family.c_str(),s,w);
}
//------------------------------------------------------------------------------
void wxCairo::setFontface(const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight)
{
cairo_select_font_face(m_cr, family, slant, weight);
}
//------------------------------------------------------------------------------
//the new font size, in user space units
void wxCairo::setFontSize(double size)
{
cairo_set_font_size(m_cr,size);
}
//------------------------------------------------------------------------------
void wxCairo::seveToPNG(std::string filePath)
{
cairo_surface_write_to_png(m_surface, filePath.c_str());
}
//------------------------------------------------------------------------------
//Ширина текста в пикселях
double wxCairo::getTextWidth(std::wstring& str)
{
std::string utf8 = convUTF16ToUTF8(str);
cairo_text_extents_t ext;
cairo_text_extents(m_cr, utf8.c_str(), &ext);
return ext.width;
}
//------------------------------------------------------------------------------
//Высота текста в пикселях
double wxCairo::getTextHeight(std::wstring& str)
{
std::string utf8 = convUTF16ToUTF8(str);
cairo_text_extents_t ext;
cairo_text_extents(m_cr, utf8.c_str(), &ext);
return ext.height;
}
//------------------------------------------------------------------------------
//Вывести текст по центру области
void wxCairo::ShowTextCenter(std::wstring& str, int xStart, int xEnd, int y)
{
std::string utf8 = convUTF16ToUTF8(str);
cairo_text_extents_t ext;
cairo_text_extents(m_cr, utf8.c_str(), &ext);
ext.width = xStart + (((xEnd - xStart) / 2.0f) - (ext.width / 2.0f));
cairo_move_to(m_cr, ext.width, y);
cairo_show_text(m_cr, utf8.c_str());
}
//------------------------------------------------------------------------------
//Вывести текст с переносом на следующую строку с выравниванием по словам, высота символов однирна
//xStart начало для вычисления центра
//xEnd конец для вычисления центра
//y высота
void wxCairo::ShowTextBR(std::wstring& str, int xStart, int xEnd, int y)
{
/*stdword line;
std::vector<stdword> parts;
int maxH=0;
std::vector<std::wstring> array =split(str,L' ');
for (std::vector<std::wstring>::iterator it = array.begin() ; it != array.end(); ++it)
{
std::wstring s=*it;
line.word = convUTF16ToUTF8(s);
cairo_text_extents(m_cr, line.word.c_str(), &line.ext);
line.ext.width+=line.ext.width/s.length(); //Так как пробел почемуто обрезается при расчёте ширины
parts.push_back(line);
if(maxH<line.ext.height) maxH=line.ext.height;
}
int w=xStart;
for (std::vector<stdword>::iterator it = parts.begin() ; it != parts.end(); ++it)
{
line=*it;
if(w+line.ext.width<xEnd)
{
cairo_move_to(m_cr, w, y);
w+=line.ext.width;
}else
{
w=xStart;
y+=maxH;
cairo_move_to(m_cr, w, y);
w+=line.ext.width;
}
cairo_show_text(m_cr, line.word.c_str());
}*/
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//Вывести текст с переносом на следующую строку с выравниванием по словам, высота символов однирна
//xStart начало для вычисления центра
//xEnd конец для вычисления центра
//y высота
void wxCairo::ShowTextCenterBR(std::wstring& str, int xStart, int xEnd, int y)
{
std::vector<std::wstring> array =split(str,L' '); //Для разбивки на слова
int height=0; //Высота символов
std::vector<stdword> parts; //Для разбивки на строки
stdword line;
line.width=0;
line.str="";
for (std::vector<std::wstring>::iterator it = array.begin() ; it != array.end(); ++it)
{
std::wstring s=*it;
std::string word = convUTF16ToUTF8(s);
cairo_text_extents_t ext;
cairo_text_extents(m_cr, word.c_str(), &ext);
ext.width+=ext.width/s.length(); //Так как пробел почемуто обрезается при расчёте ширины
if(height<ext.height) height=ext.height; //Высота символов
if(line.width+ext.width<xEnd-xStart)
{
line.width+=ext.width;
line.str+=word+' ';
}else
{
parts.push_back(line);
line.width=0;
line.str="";
}
}
parts.push_back(line);
//Отображаю текст по центру
for (std::vector<stdword>::iterator it = parts.begin() ; it != parts.end(); ++it)
{
stdword line=*it;
int width = xStart + (((xEnd - xStart) / 2.0f) - (line.width / 2.0f));
cairo_move_to(m_cr, width, y);
cairo_show_text(m_cr, line.str.c_str());
y+=height;
}
}
//------------------------------------------------------------------------------