On 1/5/2025 3:06 PM, Stefan Claas wrote:
Chris M. Thomasson wrote:
On 1/5/2025 2:48 PM, Chris M. Thomasson wrote:
On 1/5/2025 1:10 PM, Stefan Claas wrote:
Rich wrote:
Stefan Claas <pollux@tilde.club> wrote:
Rich wrote:
Stefan Claas <pollux@tilde.club> wrote:
Stefan Claas wrote:
Rich wrote:
Stefan Claas <pollux@tilde.club> wrote:
Rich wrote:
>
If instead you mean some kind of "special, PNG aware,
encryptor that only encrypted the bitmap data of a PNG",
but left the file as otherwise a proper PNG image
structure, then that is slightly tricky (and an algorithm
that is only useful for PNG's alone).
>
Yes, this is what I mean.
>
Which brings up the question of: why?
>
Why go to the trouble to create an encryptor that is
specalized for just encrypting the internal bitmap data within
a PNG, leaving the rest as a PNG file, when a generic "byte
stream" encryptor will encrypt the entire PNG with no extra
effort?
>
To make more content as allowed postable on social media, like
X.
>
I.e, first you put data with file2png in a .png and then encrypt
it to finally post it. I can do this now with my xorpic program,
but I thought a solution with AES-GCM or XChaCha20+ploy1305 is
better.
>
The "path" I outlined in my previous post, where you utilize the
netpbm image format as your 'intermediary' would allow you to use
any generic encryption routine you like, while also allowing you to
convert the encrypted binary data to/from an image format of your
choice (well, your choice within the set of other formats for which
NetPBM has to/from converters available).
>
This frees you from having to understand the internal structure of
the various image formats. You just work with the netpbm format (a
raw binary bit/pixel block) for the encrypt/decrypt/padding
operations, and delegate all the "image format" complexity to the
netpbm library.
>
Thank you! My ppmenc tool works nicely, here are the test images:
>
https://jmp.sh/HZM9ML9f
>
The big problem I face when converting the encryypted image to .png
and back a diff shows a difference and the decryption fails.
>
Maybe someone can figure out what to do, so that a converted .ppm can
be posted online , for viewers/readers and then can be converted back
to the original .ppm, which shows no difference.
>
We can't read your mind over Usenet so can you show how you converted
the encrypted image to a png and back.
>
>
I used Gimp with compression set to 0 and the netbmp tools.
>
>
You should write your own program for it. The Gimp altered some bytes,
right?
>
Fwiw, the Cairo lib is fairly nice, well, to me at least... I use it a
lot for my 2d work. it allows you to gain access to the raw underlying
buffer. So, I can create PNG's with payloads that are intact.
Ok, here is the deal ... I have file2png (Go and Python3) which converts
any (encrypted) payload to valid noise .png images and back. I have xorpng
in Go which can create .png keys of random noise (crypto/rand) and xor
then .png images with them, to create encrypted noise images. I have ppmenc
in Go which encrypts ppm (P6) images to noise images. What I can not work
out is to convert a ppm to .png and back to the *original* .ppm (P6) file,
because .png with programs used or the Go library alter the conversion,
back to .ppm (P6). I tried many things and always failed.
*Please* try to write a .ppm (P6) to .png converter (and back) in C(++)
and see if you can get the *original* data back. The sci.crypt community
and me of course would appreciate your help very much!
I can, but I am busy with other things. I wrote a PPM reader a long time ago. decades. Just parse the PPM (P6) format. Here is a program I wrote in C that stores PPM's as a series of slices for a 3d volumetric object. The ct_canvas_save_ppm creates a PPM. The fun part is that the image stack is a volumetric object that can even be made into a hologram.
_______________________
/*
A Simple 2d Plane For Owen, with proper aspect ratios!
Color adder, single channel
By: Chris M. Thomasson
*_____________________________________________________________*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <complex.h>
#include <tgmath.h>
#include <stdbool.h>
#define CT_WIDTH 1920
#define CT_HEIGHT 1080
#define CT_N 10000000
struct ct_rgb
{
unsigned char r;
unsigned char g;
unsigned char b;
};
struct ct_canvas
{
unsigned long width;
unsigned long height;
//unsigned char* buf;
struct ct_rgb* buf;
};
bool
ct_canvas_create(
struct ct_canvas* const self,
unsigned long width,
unsigned long height
){
size_t size = width * height * sizeof(*self->buf);
self->buf = calloc(1, size);
if (self->buf)
{
self->width = width;
self->height = height;
return true;
}
return false;
}
void
ct_canvas_destroy(
struct ct_canvas const* const self
){
free(self->buf);
}
bool
ct_canvas_save_ppm(
struct ct_canvas const* const self,
char const* fname
){
FILE* fout = fopen(fname, "wb");
if (fout)
{
// P6 by Bart over on:
//
https://groups.google.com/forum/#!original/comp.lang.c/4196m3Raggs/2moZ67o5EwAJ
char const ppm_head[] =
"P6\n"
"# Chris M. Thomasson Simple 2d Plane ver:0.0.0.0 (pre-alpha)";
fprintf(fout, "%s\n%lu %lu\n%u\n",
ppm_head,
self->width, self->height,
255U);
size_t size = self->width * self->height;
for (size_t i = 0; i < size; ++i)
{
//unsigned int c = self->buf[i];
struct ct_rgb* c = self->buf + i;
fprintf(fout, "%c%c%c", c->r, c->g, c->b);
//fprintf(fout, "%c%c%c", c, 0U, 0U);
}
if (! fclose(fout))
{
return true;
}
}
return false;
}
struct ct_axes
{
double xmin;
double xmax;
double ymin;
double ymax;
};
struct ct_axes
ct_axes_from_point(
double complex z,
double radius
){
struct ct_axes axes = {
creal(z) - radius, creal(z) + radius,
cimag(z) - radius, cimag(z) + radius
};
return axes;
}
struct ct_plane
{
struct ct_axes axes;
double xstep;
double ystep;
};
void
ct_plane_init(
struct ct_plane* const self,
struct ct_axes const* axes,
unsigned long width,
unsigned long height
){
self->axes = *axes;
double awidth = self->axes.xmax - self->axes.xmin;
double aheight = self->axes.ymax - self->axes.ymin;
assert(width > 0 && height > 0 && awidth > 0.0);
double daspect = fabs((double)height / width);
double waspect = fabs(aheight / awidth);
if (daspect > waspect)
{
double excess = aheight * (daspect / waspect - 1.0);
self->axes.ymax += excess / 2.0;
self->axes.ymin -= excess / 2.0;
}
else if (daspect < waspect)
{
double excess = awidth * (waspect / daspect - 1.0);
self->axes.xmax += excess / 2.0;
self->axes.xmin -= excess / 2.0;
}
self->xstep = (self->axes.xmax - self->axes.xmin) / width;
self->ystep = (self->axes.ymax - self->axes.ymin) / height;
}
struct ct_plot
{
struct ct_plane plane;
struct ct_canvas* canvas;
};
void
ct_plot_init(
struct ct_plot* const self,
struct ct_axes const* axes,
struct ct_canvas* canvas
){
ct_plane_init(&self->plane, axes, canvas->width - 1, canvas->height - 1);
self->canvas = canvas;
}
bool
ct_plot_add(
struct ct_plot* const self,
double complex z,
struct ct_rgb const* color
){
long x = (creal(z) - self->plane.axes.xmin) / self->plane.xstep;
long y = (self->plane.axes.ymax - cimag(z)) / self->plane.ystep;
if (x > -1 && x < (long)self->canvas->width &&
y > -1 && y < (long)self->canvas->height)
{
// Now, we can convert to index.
size_t i = x + y * self->canvas->width;
assert(i < self->canvas->height * self->canvas->width);
struct ct_rgb exist = self->canvas->buf[i];
exist.r += 1;
self->canvas->buf[i] = exist;
return true;
}
return true;
}
bool
ct_plot_pixel(
struct ct_plot* const self,
long x,
long y,
struct ct_rgb const* color
){
if (x > -1 && x < (long)self->canvas->width &&
y > -1 && y < (long)self->canvas->height)
{
// Now, we can convert to index.
size_t i = x + y * self->canvas->width;
assert(i < self->canvas->height * self->canvas->width);
self->canvas->buf[i] = *color;
return true;
}
return false;
}
double complex
ct_project_to_xy(
struct ct_plot* const self,
long x,
long y
){
double complex p =
(self->plane.axes.xmin + x * self->plane.xstep) +
(self->plane.axes.ymax - y * self->plane.ystep) * I;
return p;
}
bool
ct_plot_point(
struct ct_plot* const self,
double complex z,
struct ct_rgb const* color
){
long x = (creal(z) - self->plane.axes.xmin) / self->plane.xstep;
long y = (self->plane.axes.ymax - cimag(z)) / self->plane.ystep;
if (x > -1 && x < (long)self->canvas->width &&
y > -1 && y < (long)self->canvas->height)
{
// Now, we can convert to index.
size_t i = x + y * self->canvas->width;
assert(i < self->canvas->height * self->canvas->width);
self->canvas->buf[i] = *color;
return true;
}
return false;
}
// slow, so what for now... ;^)
void ct_circle(
struct ct_plot* const plot,
double complex c,
double radius,
unsigned int n
){
double abase = 6.2831853071 / n;
for (unsigned int i = 0; i < n; ++i)
{
double angle = abase * i;
double complex z =
(creal(c) + cos(angle) * radius) +
(cimag(c) + sin(angle) * radius) * I;
struct ct_rgb rgb = { 255, 255, 255 };
ct_plot_point(plot, z, &rgb);
}
}
// Simple 3-ary vector impl, just what I need.
struct ct_vec3
{
double x;
double y;
double z;
};
double ct_vev3_length(
struct ct_vec3 const p
){
double sum = p.x * p.x + p.y * p.y + p.z * p.z;
return sqrt(sum);
}
struct ct_vec3
ct_vec3_add(
struct ct_vec3 const p,
struct ct_vec3 const addend
){
struct ct_vec3 sum = {
p.x + addend.x,
p.y + addend.y,
p.z + addend.z
};
return sum;
}
// The Mandelbulb, slice hardcoded
// Animation comes next Owen.
void
ct_iterate_mbulb_pixel(
struct ct_plot* const plot,
struct ct_vec3 const z0,
struct ct_vec3 const c0,
long x,
long y,
unsigned int n
){
struct ct_vec3 zs = z0;
struct ct_vec3 cs = c0;
double power = 3.0;
for (unsigned long i = 0; i < n; ++i)
{
double r = ct_vev3_length(zs);
double rpower = pow(r, power);
double angle0 = atan2(zs.z, sqrt(zs.x * zs.x + zs.y * zs.y));
double angle1 = atan2(zs.y, zs.x);
struct ct_vec3 znew;
znew.x = rpower * cos(power * angle1) * cos(power * angle0);
znew.y = rpower * sin(power * angle1) * cos(power * angle0);
znew.z = rpower * sin(power * angle0);
zs = ct_vec3_add(znew, cs);
if (r > 2.0)
{
return;
}
}
struct ct_rgb rgb = { 0, 255, 0 };
ct_plot_pixel(plot, x, y, &rgb);
}
// Gain the field...
void
ct_iterate_mbulb_plane(
struct ct_plot* const plot,
unsigned int n
){
for (long y = 0; y < plot->canvas->height; ++y)
{
for (long x = 0; x < plot->canvas->width; ++x)
{
double complex cz = ct_project_to_xy(plot, x, y);
// Well, our per slice coords...
struct ct_vec3 z;
z.x = creal(cz);
z.y = cimag(cz);
z.z = 0.1;
// Iterate the slice
ct_iterate_mbulb_pixel(plot, z, z, x, y, n);
}
}
}
void ct_test_plane(
struct ct_plot* const plot
){
ct_iterate_mbulb_plane(plot, 64);
ct_circle(plot, 0+0*I, 1.0, 2048);
}
int main(void)
{
struct ct_canvas canvas;
if (ct_canvas_create(&canvas, CT_WIDTH, CT_HEIGHT))
{
double complex plane_origin = 0+0*I;
double plane_radius = 2.0;
struct ct_axes axes = ct_axes_from_point(plane_origin, plane_radius);
struct ct_plot plot;
ct_plot_init(&plot, &axes, &canvas);
ct_test_plane(&plot);
// Our unit circle
ct_circle(&plot, 0+0*I, 1.0, 2048);
ct_circle(&plot, 2+0*I, 2.0, 2048);
ct_circle(&plot, -2+0*I, 2.0, 2048);
ct_circle(&plot, 0+2*I, 2.0, 2048);
ct_circle(&plot, 0-2*I, 2.0, 2048);
ct_canvas_save_ppm(&canvas, "ct_plane.ppm");
ct_canvas_destroy(&canvas);
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
_______________________