I was unable to run the function written by Jens in Mathematica 12.0 cause of multiple errors caused by an altered (?) ContourPlot's realisation. So I have rewrote rotateContourLabels function to adopt it to a newer Mathatica version. For my own purposes I use the following realisation:
Clear[rotateContourLabels];
rotateContourLabels::usage =
"The function rotateContourLabels accepts the output of ContourPlot \
or ListContourPlot, assuming they were made with the option \
ContourLabel-> All. The plot is passed via the required first \
argument. The function rotates the labels of all contours to be \
approximately parallel to the iso-lines. The optional LabelFunction \
can specify a custom label style in the form of a function f[#1, #2, \
#3], where {#1, #2} is the 2D location vector of the label, and #3 \
the value of the plotted function at that location. For examples see \
the documentation on ContourLabels. The default label style is given \
by the function Text[#3,{#1,#2}]&. A second option, Alignment, \
influences the placement of the labels along the contour. The default \
Alignment -> Automatic leaves the original placement intact, any \
other value will shift the labels to an estimated center position \
along the contour.";
Options[rotateContourLabels] = {
LabelingFunction -> (Text[#3, {#1, #2}]&),
Alignment -> Automatic
};
rotateContourLabels[plot_, OptionsPattern[]] := With[{
gcIdx = Sequence[1,1], (* index of a GraphicsComplex inside a Graphics *)
ppIdx = Sequence[1 ], (* index of a list of 2d-points in the GC *)
ccIdx = Sequence[2,2], (* index of a list of contour lines in the GC *)
llIdx = Sequence[2,3], (* index of a list of labels in the GC *)
case = Identity
}, Block[{gc = plot[[gcIdx]],
pointList, contourList, labelList, contourIdxs, contourPoss, labelValues, labelIdxs,
labelPoints, getClosestLine, getClosestPoints, makeTransforms, origins, transforms,
plotRange, plotRatio, plotScale, computeLabel, rangeRatio
}, Catch[
(*-- extract basic data containters --*)
pointList = Quiet@Check[gc[[ppIdx]], plot]; (* {{x,y} ...} *)
contourList = Quiet@Check[gc[[ccIdx]], plot]; (* {{<style ...>, Line[List[..]]} ...} *)
labelList = Quiet@Check[gc[[llIdx]], plot]; (* {Inset[val, idx] ...} *)
plotRange = First /@ Differences /@ (PlotRange /. Options[plot]);
rangeRatio = plotRange[[2]] / plotRange[[1]];
plotRatio = AspectRatio /. Options[plot];
(*-- normalize extracted data --*)
contourIdxs = Cases[contourList, Line[idxs_] :> idxs, \[Infinity]]; (* {{point_idx ...} ...} *)
contourPoss = Map[pointList[[#]]&, contourIdxs, {2}];
labelValues = labelList[[;;, 1]];
labelIdxs = labelList[[;;, 2]];
labelPoints = pointList[[labelIdxs]];
If [Length@contourPoss == 0,
Return@plot
];
(*----> helper functions --*)
(** Lablel rotation angle **)
getLabelAngle = Function[{baseVector, targetVector}, With[{
(* Map targetVector to [-\[Pi], \[Pi]] angle *)
base = baseVector Sign[baseVector [[1]]],
dest = targetVector Sign[targetVector[[1]]]
}, With[{
\[Alpha] = VectorAngle[base, dest] Sign[(dest-base)[[2]]]
},
(** \[Alpha] \[LongDash] unscaled angle = arctan[y_0 / x_0]
* \[Beta] \[LongDash] scaled angle = arctan[y_1 / x_1] = arctan[y_1 / x_0]
* y_1 = ar_target x_1 = ar_target x_0
* y_0 = ar_range x_0
** => \[Beta] = arctan[ar_target/ar_range tan[\[Alpha]]] **)
ArcTan[plotRatio/rangeRatio Tan[\[Alpha]]]
]]];
(** find positions of the closest contour and the line's closest point **)
getClosestLine = Function[{idxOrPos}, Block[{},
Switch[Length @ idxOrPos
, case @ 0, Block[{idx = idxOrPos, checks, positions},
getClosestLine[pointList[[idx]]]
]
, case @ 2, Block[{pos = idxOrPos,
closestPoint, closestPoints, closestLinePos, closestPointPos
},
closestPoints = Map[First@Nearest[#1, pos]&, contourPoss];
closestPoint = First@Nearest[closestPoints, pos];
closestLinePos = Position[closestPoints, closestPoint][[1,1]];
closestPointPos = Position[contourPoss[[closestLinePos]], closestPoint][[1,1]];
{closestLinePos, closestPointPos}
]
, _, Throw[{"unsupported index ot position type ", idxOrPos}]
]
]];
(** the function finds points linked to a specified point **)
getClosestPoints = Function[{linePos, pointPos}, Block[{idxs,
lineLen = Length@contourIdxs[[linePos]]
},
idxs = With[{alignment = OptionValue[Alignment]}, Switch[alignment
, Automatic, {-1, 0, 1} + pointPos
, Center , {-1, 0, 1} + \[LeftFloor]lineLen/2\[RightFloor]
, _, Throw[{"Unsupported Alignment type ", OptionValue[Alignment]}]
]];
idxs = idxs /. a_?(# < 1 || # > lineLen&) -> None;
idxs
]];
(** the function calclates a geometry transformation and a new label origin **)
makeTransforms = Function[{pos}, Block[{
idxOr2DPos, linePos, pointPos, basePointPoss, originPoint,
basePointIdxs, secantVector, pointCoords, basePoints, transform
},
(* >> get closest points to a target label anchor *)
{linePos, pointPos} = getClosestLine[labelIdxs[[pos]]];
basePointPoss = getClosestPoints[linePos, pointPos];
basePointIdxs = If[# =!= None, contourIdxs[[linePos, #]], None]& /@ basePointPoss;
basePoints = If[# =!= None, pointList[[#]]]& /@ basePointIdxs;
originPoint = basePoints[[2]];
basePoints = DeleteCases[basePoints, None];
Assert[Length@basePoints >= 2];
(* >> compute an right-direction-vector *)
secantVector = basePoints[[-1]] - basePoints[[1]];
(* >> composite a rotation operator *)
With[{
angle = getLabelAngle[{1, 0}, secantVector],
origin = originPoint
},
transform = Rotate[#, angle]&;
];
{originPoint, transform}
]];
computeLabel = Function[{x, y, labelValue, transform}, Block[{label},
label = Replace[OptionValue[LabelingFunction][x, y, labelValue]
, {
Text[v_, p_List, o_List, r___] :> Text[v, r],
Text[v_, p_List, r___] :> Text[v, r],
Text[v_, r___] :> Text[v, r]
}
];
Text[transform @ label, {x, y}]
]];
(*----< helper functions --*)
(*-- main: transform original plot's labels --*)
{origins, transforms} = Map[makeTransforms, Range[Length@labelPoints]]\[Transpose];
ReplacePart[plot, {gcIdx, llIdx} -> MapThread[computeLabel
, Join[origins\[Transpose], {labelValues, transforms}]
]]
]]]
As a result it's possible to get the same result on the presented examples like
c = ContourPlot[x y, {x, -2, 2}, {y, -2, 2}
, ContourShading -> False
, Contours -> 10
, ContourLabels -> All
, Background -> White
];
rotateContourLabels[c
, Alignment -> Center
, LabelingFunction -> (Text[#3, {#1, #2}, Background -> White] &)
]

and
a = ContourPlot[Im[(x + I y)^(1/2)], {x, -1, 1}, {y, -1, 1}
, Contours -> 20
, ContourLabels -> True
, Background->White
];
rotateContourLabels[a
, Alignment -> Center
, LabelingFunction -> (Text[#3, {#1, #2}
, Background -> Directive[Opacity[.5], White]
] &)
]

Edited:
Also, Mathemarica tries to adjust plot's aspect ratio to a specified value (Option: AspectRatio). The adjustment shears all plot contents, including all rotated lables (Text[..] filds are not sheared). To prevent labels from transformations I've started to wrap labels into a Text[, {position}] command, where can be Rotate[Text["lebel"], angle].
The artifact was clearly visible in plots where max[x_y_range] / min[x_y_range] >> 1
With[{
equation = Subscript[\[Sigma], sb] (Subscript[\[Epsilon], w] Subscript[T, w]^4 - Subscript[\[Epsilon], 0] Subscript[T, 0]^4) + h (Subscript[T, w] - Subscript[T, 0]) /. {
Subscript[\[Sigma], sb] -> 5.670373 10^-8,
Subscript[T, 0] -> 273,
Subscript[\[Epsilon], 0] -> 0.95,
Subscript[\[Epsilon], w] -> 0.35
},
vars = Sequence[{h, 2, 10}, {Subscript[T, w], 273, 273 + 100}]
},
d = ContourPlot[equation, vars
, ContourLabels -> All
, Contours -> 10
, Background -> White
];
d = rotateContourLabels[d
, Alignment -> Center
, LabelingFunction -> (Text[" " <> ToString@#3 <> " ", {#1, #2}
, Background -> Directive[Opacity[.8], White]
]&)
]
]
