You appear to have got your channels mixed up. You are treating the input as RGBA when you say it is ARGB. In any case, your code using div and mod is inefficent. Bitwise shifting is the idiomatic way.
You can do it like this for ARGB input:
procedure ARGBtoColorChannels(ARGB: DWORD; out A, R, G, B: Byte);
begin
A := Byte(ARGB);
R := Byte(ARGB shr 8);
G := Byte(ARGB shr 16);
B := Byte(ARGB shr 24);
end;
Or if you start with RGBA then it goes like this:
procedure RGBAtoColorChannels(RGBA: DWORD; out A, R, G, B: Byte);
begin
R := Byte(RGBA);
G := Byte(RGBA shr 8);
B := Byte(RGBA shr 16);
A := Byte(RGBA shr 24);
end;
And these are little endian versions, since Delphi only targets on little endian machines, at the time of writing.
If you are looking for a function to convert ARGB to RGBA then you can make one like so:
function ARGBtoRGBA(ARGB: DWORD): DWORD;
var
A, R, G, B: Byte;
begin
ARGBtoColorChannels(ARGB, A, R, G, B);
Result := R or (G shl 8) or (B shl 16) or (A shl 24);
end;
And for completeness the reverse is:
function RGBAtoARGB(RGBA: DWORD): DWORD;
var
A, R, G, B: Byte;
begin
RGBAtoColorChannels(RGBA, A, R, G, B);
Result := A or (R shl 8) or (G shl 16) or (B shl 24);
end;
In order for you to know what to do, you need to understand what buf is. Is it ARGB or RGBA? Assuming it it ARGB, which seems likely given the content of your question, you are attempting to copy to RowPtr, which also appears to be ARGB. In which case you can blit the color like this:
PInteger(RowPtr)^ := buf[buf_pos];
I would also strongly recommend that you change the type of the buf parameter. An unsigned type is better here, because you may need to perform bitwise operations. What's more you are copying the entire array via the stack which is very inefficient. For large bitmaps you will suffer stack overflow. Instead that parameter should be:
const buf: array of DWORD;
or
const buf: array of Cardinal;
Using const means that a reference to the array is passed, rather than a copy.
You may as well avoid using PRGBQuad and declare RowPtr to be of type PCardinal, say.
Then you can assign like this:
RowPtr^ := buf[buf_pos];
At that point you don't need to do it pixel by pixel. You can copy an entire scanline with Move because this is a simply blit.
for y := offY to offY + height - 1 do
begin
RowPtr := formMain.imgPreview.Bitmap.ScanLine[y];
Inc(RowPtr, offX);
Move(buf[buf_pos], RowPtr^, width*SizeOf(RowPtr^));
Inc(buf_pos, width);
end;
Calling Refresh and Update seems pointless. I'm not sure you need to call either, but if you do, just call Invalidate instead!