Я реализовал довольно рудиментарный метод «Justify» для рисования строки, однако я хотел бы оптимизировать его, чтобы расстояние было немного более рассредоточенным.
Что у меня есть до сих пор, это:
string lastword = line.Split(' ').Last();
string lineNoLastWord = line.Substring(0,line.LastIndexOf(" ")).Trim();;
g.DrawString( lineNoLastWord, Font, brush, textBounds, sf );
g.DrawString( lastword, Font, brush, textBounds, ConvertAlignment( System.Windows.TextAlignment.Right ) );
ConvertAlignment
— это настраиваемый метод следующим образом:
private StringFormat ConvertAlignment(System.Windows.TextAlignment align) {
StringFormat s = new StringFormat();
switch ( align ) {
case System.Windows.TextAlignment.Left:
case System.Windows.TextAlignment.Justify:
s.LineAlignment=StringAlignment.Near;
break;
case System.Windows.TextAlignment.Right:
s.LineAlignment=StringAlignment.Far;
break;
case System.Windows.TextAlignment.Center:
s.LineAlignment=StringAlignment.Center;
break;
}
s.Alignment = s.LineAlignment;
return s;
}
Результат близок, но требует некоторой корректировки пробелов в строке lineNoLastWord
.
Еще немного предыстории кода. line
является результатом метода, который отвечает за обнаружение того, выходит ли строка за границы (ширины), и разбивает ее на строки и слова, разбивая и измеряя по мере ее продвижения, чтобы убедиться, что вся строка остается в пределах ширины области для быть нарисованы. Метод реализует другие свойства в гораздо большем классе, но вот его суть:
internal LineBreaker breakIntoLines( string s, int maxLineWidth ) {
List<string> sResults = new List<string>();
int stringHeight;
int lineHeight;
int maxWidthPixels = maxLineWidth;
string[] lines = s.Split(new string[] { "\n", "\r\n" }, StringSplitOptions.None);
using ( Graphics g=Graphics.FromImage( Pages[CurrentPage - 1] ) ) {
g.CompositingQuality = CompositingQuality.HighQuality;
if ( maxLineWidth<=0||maxLineWidth>( Pages[CurrentPage-1].Width-X ) ) {
maxWidthPixels=Pages[CurrentPage-1].Width-X;
}
lineHeight = (Int32)( g.MeasureString( "X", Font ).Height*(float)( (float)LineSpacing/(float)100 ) );
stringHeight = (Int32)g.MeasureString( "X", Font ).Height;
foreach ( string line in lines ) {
string[] words=line.Split( new string[] { " " }, StringSplitOptions.None );
sResults.Add( "" );
for ( int i=0; i<words.Length; i++ ) {
if ( sResults[sResults.Count-1].Length==0 ) {
sResults[sResults.Count-1]=words[i];
} else {
if ( g.MeasureString( sResults[sResults.Count-1]+" "+words[i], Font ).Width<maxWidthPixels ) {
sResults[sResults.Count-1]+=" "+words[i];
} else {
sResults.Add( words[i] );
}
}
}
}
}
return new LineBreaker() {
LineHeight = lineHeight,
StringHeight = stringHeight,
MaxWidthPixels = maxWidthPixels,
Lines = sResults
};
}
internal class LineBreaker {
public List<string> Lines { get; set; }
public int MaxWidthPixels { get; set; }
public int StringHeight { get; set; }
public int LineHeight { get; set; }
public LineBreaker() {
Lines = new List<string>();
MaxWidthPixels = 0;
StringHeight = 0;
LineHeight = 0;
}
public LineBreaker( List<string> lines, int maxWidthPixels, int stringHeight, int lineHeight ) {
Lines = lines;
MaxWidthPixels = maxWidthPixels;
LineHeight = lineHeight;
StringHeight = stringHeight;
}
}
На следующем изображении показана проблема, которую это вызывает:
Я также видел этот вопрос и ответы на stackoverflow и обнаружил, что он также является неэффективным способом пробела из-за неизвестного размера строки, а неизвестная ширина документа приведет к тому, что строка будет слишком длинной, если слишком много слов, или слишком короткой без правильного обоснования. Полное выравнивание означает, что текст выровнен как по левой, так и по правой стороне, и, как правило, содержимое внутри находится на максимально возможном равномерном расстоянии друг от друга. Вот как я хотел бы это реализовать.
Решение, скорее всего, заключается в вычислении строк lastWord
и lineNoLastWord
с некоторыми измерениями, чтобы гарантировать жизнеспособность вывода в том смысле, что никакие два слова в строке не будут совпадать или объединяться, и не будет отступов. правая сторона, однако левая, может по-прежнему содержать отступ или вкладку. Другая часть, которую следует учитывать, заключается в том, что если строка короче определенного порога, то не следует применять обоснование.
ОБНОВЛЕНИЕ
У меня есть следующая концепция, которая должна работать, просто нужно получить слово из указанного индекса и вставить правильный пробел:
int lastwordwidth = (Int32)g.MeasureString(" " + lastword, Font).Width;
int extraspace=lines.MaxWidthPixels-(Int32)( g.MeasureString( " "+lineNoLastWord, Font ).Width+lastwordwidth );
int totalspacesneeded = (Int32)Math.Floor((decimal)(extraspace / lines.SpaceWidth));
int spacecount = lineNoLastWord.Count(x => x == ' ');
int currentwordspace = 0;
for ( int i=0; i<spacecount; i++ ) {
if ( currentwordspace>spacecount ) { currentwordspace = 0; }
// insert spaces where spaces already exist between each word
// use currentwordspace to determine which word to replace with a word and another space
if ( currentwordspace==0 ) {
// insert space after word
} else {
// insert space before word
}
currentwordspace++;
}
newpage
позволяет рисовать всю графику на страницах без предварительного вызова печати (об этом говорилось в других несвязанных сообщениях). Прямо сейчас я просто застрял на(Int32)Math.Ceiling((decimal)(extraspace / lines.SpaceWidth))
, всегда возвращает только1
, гдеextraspace
равно 49, аlines.SpaceWidth
равно 31. Кроме того, у меня не было проблем с рисованием/позиционированием с мерной строкой, так как я позабочусь о том, чтобы dpi/и т. д. соответствовали. - person Kraang Prime   schedule 07.04.2016int totalspacesneeded=(Int32)Math.Ceiling( (decimal)extraspace/(decimal)lines.SpaceWidth );
это то, что должно быть - person Kraang Prime   schedule 07.04.2016